matos/core/mem.c

175 lines
4.1 KiB
C
Raw Normal View History

2018-08-06 18:41:45 +02:00
#include "mem.h"
2021-04-10 00:24:02 +02:00
#include "assert.h"
2020-08-28 22:38:05 +02:00
#include "kernel.h"
#include "klibc.h"
2018-08-09 22:19:34 +02:00
#include "list.h"
#include "types.h"
2018-08-06 18:41:45 +02:00
2021-04-10 21:53:03 +02:00
static struct phyMemDesc *pageDesc = (struct phyMemDesc *)&__ld_kernel_end;
static struct phyMemDesc *phyFreePage;
static struct phyMemDesc *phyUsedPage;
2021-01-23 21:51:00 +01:00
paddr_t pageDescEnd;
paddr_t upperMem;
2018-08-09 22:19:34 +02:00
static unsigned long allocatedPage = 0;
2021-04-10 00:24:02 +02:00
int memSetup(paddr_t upperMemKB, paddr_t *firstUsed, paddr_t *lastMemUsedOut)
2018-08-06 18:41:45 +02:00
{
2021-04-10 21:53:03 +02:00
list_init(phyFreePage);
list_init(phyUsedPage);
2021-01-22 22:59:45 +01:00
// Align upper mem (in kB) on page size even if it does loose a page
2021-01-23 21:51:00 +01:00
upperMemKB = ALIGN_DOWN(upperMemKB, PAGE_SIZE / 1024);
2021-01-23 00:42:09 +01:00
unsigned long nbPage = ((upperMemKB) / (PAGE_SIZE / 1024));
2021-01-22 22:59:45 +01:00
2021-01-23 21:21:13 +01:00
printf("Available Mem from 0x%x to 0x%x: %dMB in %d Pages of %dB\n", &__ld_kernel_end,
2021-01-23 00:42:09 +01:00
upperMemKB * 1024, (upperMemKB * 1024 - (uint32_t)&__ld_kernel_end) / (1024 * 1024),
2021-01-22 22:59:45 +01:00
nbPage, PAGE_SIZE);
// Memory description is stored after the kernel. We need some place to store it
2021-04-10 21:53:03 +02:00
pageDescEnd = (unsigned long)pageDesc + nbPage * sizeof(struct phyMemDesc);
2021-01-23 21:51:00 +01:00
*lastMemUsedOut = ALIGN(pageDescEnd, PAGE_SIZE);
upperMem = upperMemKB * 1024;
2021-04-10 00:24:02 +02:00
*firstUsed = ALIGN_DOWN((paddr_t)&__ld_kernel_begin, PAGE_SIZE);
// Remove addr from 0 to PAGE_SIZE so we can return 0 for no page available
memAddBank(0, PAGE_SIZE, 0);
memAddBank(*lastMemUsedOut, *lastMemUsedOut, 0);
2021-01-22 22:59:45 +01:00
2021-01-23 00:42:09 +01:00
return 0;
}
int memAddBank(paddr_t bottomMem, paddr_t topMem, int isFree)
{
2021-01-23 21:51:00 +01:00
topMem = min(topMem, upperMem);
2021-01-23 00:42:09 +01:00
for (uint i = (bottomMem >> PAGE_SHIFT); i < (topMem >> PAGE_SHIFT); i++) {
2021-04-10 21:53:03 +02:00
struct phyMemDesc *mem = &pageDesc[i];
2021-01-23 00:42:09 +01:00
if (isFree) {
mem->ref = 0;
2021-04-10 21:53:03 +02:00
list_add_tail(phyFreePage, mem);
2021-01-23 00:42:09 +01:00
} else {
mem->ref = 1;
2021-04-10 21:53:03 +02:00
list_add_tail(phyUsedPage, mem);
}
mem->phy_addr = i * PAGE_SIZE;
}
2021-01-23 00:42:09 +01:00
return 0;
2018-08-06 18:41:45 +02:00
}
2018-08-09 22:19:34 +02:00
2021-01-23 21:51:00 +01:00
void memGetStat(uint *free, uint *used)
{
uint idx;
2021-04-10 21:53:03 +02:00
struct phyMemDesc *mem;
list_foreach(phyFreePage, mem, idx)
2021-01-23 21:51:00 +01:00
{
continue;
}
*free = idx;
2021-04-10 21:53:03 +02:00
list_foreach(phyUsedPage, mem, idx)
2021-01-23 21:51:00 +01:00
{
continue;
}
*used = idx;
}
2021-04-10 21:53:03 +02:00
struct phyMemDesc *addr2memDesc(paddr_t addr)
2018-08-09 22:19:34 +02:00
{
int idx = addr >> PAGE_SHIFT;
2021-01-22 22:59:45 +01:00
return pageDesc + idx;
2018-08-09 22:19:34 +02:00
}
2021-04-10 21:53:03 +02:00
struct phyMemDesc *memFindConsecutiveFreePage(uint nbPage)
2018-08-09 22:19:34 +02:00
{
2021-04-10 21:53:03 +02:00
struct phyMemDesc *mem, *head;
2020-08-28 22:38:05 +02:00
uint memIdx, count;
2021-04-10 21:53:03 +02:00
if (list_is_empty(phyFreePage)) {
2020-08-28 22:38:05 +02:00
return NULL;
}
count = 1;
memIdx = 0;
2021-04-10 21:53:03 +02:00
head = phyFreePage;
mem = phyFreePage;
2020-08-28 22:38:05 +02:00
2021-04-10 21:53:03 +02:00
while (count < nbPage && (!memIdx || mem != phyFreePage)) {
2020-08-28 22:38:05 +02:00
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)
{
2021-04-10 21:53:03 +02:00
struct phyMemDesc *mem, *head, *next;
2020-08-28 22:38:05 +02:00
uint count;
head = memFindConsecutiveFreePage(nbPage);
if (head == NULL) {
pr_devel("Cannot find %d consecutive page\n", nbPage);
return (unsigned long)NULL;
}
2020-08-28 22:38:05 +02:00
mem = head;
next = head->next;
for (count = 0; count < nbPage; count++) {
2021-04-10 21:53:03 +02:00
list_delete(phyFreePage, mem);
2020-08-28 22:38:05 +02:00
mem->ref = 1;
2021-04-10 21:53:03 +02:00
list_add_tail(phyUsedPage, mem);
2020-08-28 22:38:05 +02:00
mem = next;
next = mem->next;
}
allocatedPage += nbPage;
return head->phy_addr;
2018-08-09 22:19:34 +02:00
}
int unrefPhyPage(paddr_t addr)
2018-08-09 22:19:34 +02:00
{
2021-04-10 21:53:03 +02:00
struct phyMemDesc *mem = addr2memDesc(addr);
if (!mem) {
return -1;
}
2021-04-10 00:24:02 +02:00
assert(mem->ref > 0);
mem->ref--;
if (mem->ref == 0) {
allocatedPage--;
2021-04-10 21:53:03 +02:00
list_delete(phyUsedPage, mem);
list_add_tail(phyFreePage, mem); // TODO find the right place to keep free_page sorted;
}
2018-08-09 22:19:34 +02:00
return mem->ref;
2018-08-09 22:19:34 +02:00
}
2018-11-09 17:07:39 +01:00
int refPhyPage(paddr_t addr)
2018-11-09 17:07:39 +01:00
{
2021-04-10 21:53:03 +02:00
struct phyMemDesc *mem = addr2memDesc(addr);
if (!mem) {
return -1;
}
mem->ref++;
if (mem->ref == 1) {
allocatedPage++;
2021-04-10 21:53:03 +02:00
list_add_tail(phyUsedPage, mem);
list_delete(phyFreePage, mem);
}
2018-11-09 17:07:39 +01:00
return 0;
2018-11-09 17:07:39 +01:00
}
unsigned long getNbAllocatedPage(void)
{
return allocatedPage;
}