2021-02-10 23:22:57 +01:00
|
|
|
#include "allocArea.h"
|
|
|
|
#include "alloc.h"
|
|
|
|
#include "assert.h"
|
2021-10-28 23:18:05 +02:00
|
|
|
#include "irq.h"
|
2021-10-28 23:49:58 +02:00
|
|
|
#include "kernel.h"
|
2021-02-10 23:22:57 +01:00
|
|
|
#include "list.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "stdarg.h"
|
|
|
|
|
2023-05-01 17:58:35 +02:00
|
|
|
struct memArea {
|
|
|
|
vaddr_t startAddr;
|
|
|
|
uint nbPages;
|
|
|
|
|
|
|
|
struct memArea *next;
|
|
|
|
struct memArea *prev;
|
|
|
|
};
|
|
|
|
|
2021-02-10 23:22:57 +01:00
|
|
|
static struct memArea *freeArea;
|
|
|
|
static struct memArea *usedArea;
|
|
|
|
|
2021-11-12 10:19:43 +01:00
|
|
|
static int areaMergeFreeArea(struct memArea *prev, struct memArea **next);
|
2021-08-09 09:26:10 +02:00
|
|
|
|
2021-10-28 00:32:35 +02:00
|
|
|
void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stackBottom, vaddr_t stackTop)
|
2021-02-10 23:22:57 +01:00
|
|
|
{
|
|
|
|
list_init(freeArea);
|
|
|
|
list_init(usedArea);
|
2021-08-09 09:26:10 +02:00
|
|
|
|
|
|
|
vaddr_t areaAddr, descAddr, entryAddr;
|
|
|
|
allocSetup(sizeof(struct memArea), &areaAddr, &descAddr, &entryAddr);
|
2021-10-28 18:33:02 +02:00
|
|
|
areaAdd(descAddr, descAddr + PAGE_SIZE, FALSE);
|
2021-08-09 09:26:10 +02:00
|
|
|
if (entryAddr != descAddr)
|
2021-10-28 18:33:02 +02:00
|
|
|
areaAdd(entryAddr, entryAddr + PAGE_SIZE, FALSE);
|
2021-08-09 09:26:10 +02:00
|
|
|
if (areaAddr != descAddr && areaAddr != entryAddr)
|
2021-10-28 18:33:02 +02:00
|
|
|
areaAdd(areaAddr, areaAddr + PAGE_SIZE, FALSE);
|
2021-08-19 16:44:47 +02:00
|
|
|
|
2021-10-28 23:49:58 +02:00
|
|
|
// kernel bootstrap part
|
2021-10-28 18:33:02 +02:00
|
|
|
areaAdd(ALIGN_DOWN(firstMemUsed, PAGE_SIZE), stackBottom, FALSE);
|
2021-10-28 18:19:35 +02:00
|
|
|
|
2021-10-28 23:49:58 +02:00
|
|
|
// Initial kernel stack
|
2021-10-28 18:33:02 +02:00
|
|
|
areaAdd(stackBottom, stackTop, FALSE);
|
2021-10-28 18:19:35 +02:00
|
|
|
|
|
|
|
// Rest of kernel code
|
2021-10-28 18:33:02 +02:00
|
|
|
areaAdd(stackTop, lastUsed, FALSE);
|
2021-10-28 18:19:35 +02:00
|
|
|
|
|
|
|
// Rest of virtual mem is free
|
2021-10-28 18:33:02 +02:00
|
|
|
areaAdd(areaAddr + PAGE_SIZE, AREA_MEM_TOP, TRUE);
|
2021-10-28 18:19:35 +02:00
|
|
|
|
|
|
|
// Create allocBank for the rest of the system
|
2021-08-09 09:26:10 +02:00
|
|
|
allocPopulate();
|
2021-02-10 23:22:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
struct memArea *areaFindFit(unsigned int nbPages)
|
|
|
|
{
|
|
|
|
struct memArea *area;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
list_foreach(freeArea, area, count)
|
|
|
|
{
|
|
|
|
if (area->nbPages >= nbPages)
|
|
|
|
return area;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-08-19 16:44:47 +02:00
|
|
|
static void insertSorted(struct memArea **list, struct memArea *item)
|
2021-02-10 23:22:57 +01:00
|
|
|
{
|
2021-11-13 08:31:05 +01:00
|
|
|
struct memArea *prevArea, *cur;
|
2021-02-10 23:22:57 +01:00
|
|
|
int count;
|
2021-11-13 08:31:05 +01:00
|
|
|
prevArea = NULL;
|
2021-02-10 23:22:57 +01:00
|
|
|
|
2021-08-19 16:44:47 +02:00
|
|
|
list_foreach(*list, cur, count)
|
2021-02-10 23:22:57 +01:00
|
|
|
{
|
|
|
|
if (cur->startAddr > item->startAddr)
|
|
|
|
break;
|
2021-11-13 08:31:05 +01:00
|
|
|
prevArea = cur;
|
2021-02-10 23:22:57 +01:00
|
|
|
}
|
2021-11-13 08:31:05 +01:00
|
|
|
if (prevArea)
|
|
|
|
list_insert_after(*list, prevArea, item);
|
2021-02-10 23:22:57 +01:00
|
|
|
else
|
2021-11-13 08:31:05 +01:00
|
|
|
list_add_head(*list, item);
|
2021-02-10 23:22:57 +01:00
|
|
|
}
|
|
|
|
|
2021-10-28 23:49:58 +02:00
|
|
|
vaddr_t areaBook(unsigned int nbPages, uint32_t flags)
|
|
|
|
{
|
2021-10-28 23:18:05 +02:00
|
|
|
|
|
|
|
struct memArea *area;
|
|
|
|
vaddr_t allocated;
|
|
|
|
uint32_t irqFlags;
|
|
|
|
|
|
|
|
disable_IRQs(irqFlags);
|
|
|
|
|
|
|
|
area = areaFindFit(nbPages);
|
2021-10-28 23:49:58 +02:00
|
|
|
if (!area) {
|
2021-10-28 23:18:05 +02:00
|
|
|
printf("NULL<\n");
|
|
|
|
restore_IRQs(irqFlags);
|
|
|
|
|
|
|
|
return (vaddr_t)NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (area->nbPages == nbPages) {
|
|
|
|
list_delete(freeArea, area);
|
|
|
|
allocated = area->startAddr;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
allocated = area->startAddr;
|
|
|
|
|
|
|
|
area->nbPages -= nbPages;
|
|
|
|
area->startAddr += nbPages * PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & AREA_PHY_MAP) {
|
|
|
|
for (uint i = 0; i < nbPages; i++) {
|
|
|
|
paddr_t page = allocPhyPage(1);
|
|
|
|
if (page) {
|
2021-10-28 23:49:58 +02:00
|
|
|
if (pageMap(allocated + i * PAGE_SIZE, page, PAGING_MEM_WRITE)) {
|
|
|
|
unrefPhyPage(page);
|
|
|
|
page = (paddr_t)NULL;
|
|
|
|
} else {
|
|
|
|
unrefPhyPage(page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (page == (paddr_t)NULL) {
|
2021-10-29 23:06:03 +02:00
|
|
|
areaFree(allocated);
|
2021-10-28 23:49:58 +02:00
|
|
|
restore_IRQs(irqFlags);
|
2021-10-29 23:06:03 +02:00
|
|
|
|
2021-10-28 23:49:58 +02:00
|
|
|
return (vaddr_t)NULL;
|
2021-10-28 23:18:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
restore_IRQs(irqFlags);
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
2021-10-26 22:29:51 +02:00
|
|
|
vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags)
|
2021-02-10 23:22:57 +01:00
|
|
|
{
|
|
|
|
struct memArea *area, *allocated;
|
2021-10-28 23:18:05 +02:00
|
|
|
uint32_t irqFlags;
|
|
|
|
|
|
|
|
disable_IRQs(irqFlags);
|
2021-02-10 23:22:57 +01:00
|
|
|
|
|
|
|
area = areaFindFit(nbPages);
|
2021-10-28 23:49:58 +02:00
|
|
|
if (!area) {
|
2021-10-28 23:18:05 +02:00
|
|
|
restore_IRQs(irqFlags);
|
|
|
|
|
2021-02-10 23:22:57 +01:00
|
|
|
return (vaddr_t)NULL;
|
2021-10-28 23:18:05 +02:00
|
|
|
}
|
2021-02-10 23:22:57 +01:00
|
|
|
|
|
|
|
if (area->nbPages == nbPages) {
|
|
|
|
list_delete(freeArea, area);
|
2021-08-19 16:44:47 +02:00
|
|
|
insertSorted(&usedArea, area);
|
2021-02-10 23:22:57 +01:00
|
|
|
allocated = area;
|
2021-10-26 22:29:51 +02:00
|
|
|
} else {
|
|
|
|
struct memArea *newArea = (struct memArea *)malloc(sizeof(struct memArea));
|
|
|
|
if (!newArea) {
|
|
|
|
pr_devel("Failed to allocated area of %d pages\n", nbPages);
|
2021-10-28 23:18:05 +02:00
|
|
|
restore_IRQs(irqFlags);
|
2021-10-26 22:29:51 +02:00
|
|
|
return (vaddr_t)NULL;
|
|
|
|
}
|
2021-02-10 23:22:57 +01:00
|
|
|
|
2021-10-26 22:29:51 +02:00
|
|
|
// Avoid insertSorted(freeArea, newArea) call by modifying area
|
2021-02-10 23:22:57 +01:00
|
|
|
|
2021-10-26 22:29:51 +02:00
|
|
|
newArea->nbPages = nbPages;
|
|
|
|
newArea->startAddr = area->startAddr;
|
2021-02-10 23:22:57 +01:00
|
|
|
|
2021-10-26 22:29:51 +02:00
|
|
|
area->nbPages -= nbPages;
|
|
|
|
area->startAddr += nbPages * PAGE_SIZE;
|
2021-02-10 23:22:57 +01:00
|
|
|
|
2021-10-26 22:29:51 +02:00
|
|
|
insertSorted(&usedArea, newArea);
|
2021-02-10 23:22:57 +01:00
|
|
|
|
2021-10-26 22:29:51 +02:00
|
|
|
allocated = newArea;
|
|
|
|
}
|
2021-02-10 23:22:57 +01:00
|
|
|
|
2021-10-26 22:29:51 +02:00
|
|
|
if (flags & AREA_PHY_MAP) {
|
|
|
|
for (uint i = 0; i < nbPages; i++) {
|
|
|
|
paddr_t page = allocPhyPage(1);
|
|
|
|
if (page) {
|
2021-10-28 23:49:58 +02:00
|
|
|
if (pageMap(allocated->startAddr + i * PAGE_SIZE, page, PAGING_MEM_WRITE)) {
|
|
|
|
page = (paddr_t)NULL;
|
|
|
|
} else {
|
|
|
|
unrefPhyPage(page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (page == (paddr_t)NULL) {
|
2021-10-29 23:06:03 +02:00
|
|
|
areaFree(allocated->startAddr);
|
2021-10-28 23:49:58 +02:00
|
|
|
restore_IRQs(irqFlags);
|
2021-10-29 23:06:03 +02:00
|
|
|
|
2021-10-28 23:49:58 +02:00
|
|
|
return (vaddr_t)NULL;
|
2021-10-26 22:29:51 +02:00
|
|
|
}
|
2021-02-10 23:22:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-28 23:18:05 +02:00
|
|
|
restore_IRQs(irqFlags);
|
2021-02-10 23:22:57 +01:00
|
|
|
return allocated->startAddr;
|
|
|
|
}
|
|
|
|
|
2021-10-28 18:33:02 +02:00
|
|
|
int areaAdd(vaddr_t start, vaddr_t end, int isFree)
|
2021-08-09 09:26:10 +02:00
|
|
|
{
|
2021-08-19 16:44:47 +02:00
|
|
|
struct memArea **area;
|
2021-08-09 09:26:10 +02:00
|
|
|
|
2021-10-28 23:49:58 +02:00
|
|
|
int nbPages = (end - start) / PAGE_SIZE;
|
2023-11-09 20:30:09 +01:00
|
|
|
pr_devel("Add %s area 0x%p->0x%p (%d)\n", isFree ? "free" : "used", (void *)start, (void *)end, nbPages);
|
2021-10-28 18:33:02 +02:00
|
|
|
|
2021-10-28 23:49:58 +02:00
|
|
|
assert(nbPages > 0);
|
2021-10-28 18:33:02 +02:00
|
|
|
assert(IS_ALIGNED(start, PAGE_SIZE));
|
|
|
|
assert(IS_ALIGNED(end, PAGE_SIZE));
|
|
|
|
|
2021-08-09 09:26:10 +02:00
|
|
|
struct memArea *newArea = (struct memArea *)malloc(sizeof(struct memArea));
|
|
|
|
if (!newArea)
|
|
|
|
return (vaddr_t)NULL;
|
|
|
|
|
|
|
|
newArea->nbPages = nbPages;
|
2021-10-28 18:33:02 +02:00
|
|
|
newArea->startAddr = start;
|
2021-08-09 09:26:10 +02:00
|
|
|
|
|
|
|
if (isFree) {
|
2021-08-19 16:44:47 +02:00
|
|
|
area = &freeArea;
|
2021-08-09 09:26:10 +02:00
|
|
|
} else {
|
2021-08-19 16:44:47 +02:00
|
|
|
area = &usedArea;
|
2021-08-09 09:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
insertSorted(area, newArea);
|
|
|
|
|
|
|
|
if (isFree) {
|
|
|
|
if (newArea->prev)
|
2021-11-12 10:19:43 +01:00
|
|
|
areaMergeFreeArea(newArea->prev, area);
|
2021-08-09 09:26:10 +02:00
|
|
|
|
2021-11-13 08:31:05 +01:00
|
|
|
if (newArea && newArea->next)
|
2021-11-12 10:19:43 +01:00
|
|
|
areaMergeFreeArea(*area, &(newArea->next));
|
2021-08-09 09:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-11-13 08:31:05 +01:00
|
|
|
static int areaMergeFreeArea(struct memArea *prevArea, struct memArea **nextArea)
|
2021-02-10 23:22:57 +01:00
|
|
|
{
|
2021-11-13 08:31:05 +01:00
|
|
|
if (prevArea->startAddr + prevArea->nbPages * PAGE_SIZE != (*nextArea)->startAddr) {
|
2021-02-10 23:22:57 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2021-11-13 08:31:05 +01:00
|
|
|
struct memArea *toDelete = *nextArea;
|
2021-02-10 23:22:57 +01:00
|
|
|
|
2021-11-13 08:31:05 +01:00
|
|
|
prevArea->nbPages += (*nextArea)->nbPages;
|
|
|
|
list_delete(freeArea, toDelete);
|
|
|
|
free(*nextArea);
|
2021-02-10 23:22:57 +01:00
|
|
|
|
2021-11-13 08:31:05 +01:00
|
|
|
*nextArea = prevArea;
|
2021-02-10 23:22:57 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct memArea *areaFindMemArea(struct memArea *list, vaddr_t addr)
|
|
|
|
{
|
|
|
|
struct memArea *area;
|
|
|
|
int count;
|
|
|
|
list_foreach(list, area, count)
|
|
|
|
{
|
2021-10-26 21:42:57 +02:00
|
|
|
if (area->startAddr <= addr && addr < area->startAddr + area->nbPages * PAGE_SIZE)
|
2021-02-10 23:22:57 +01:00
|
|
|
return area;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int areaFree(vaddr_t addr)
|
|
|
|
{
|
|
|
|
struct memArea *area;
|
|
|
|
|
|
|
|
area = areaFindMemArea(usedArea, addr);
|
|
|
|
if (!area) {
|
2023-11-09 20:30:09 +01:00
|
|
|
pr_info("Cannot find memArea associated to %p\n", (void *)addr);
|
2021-02-10 23:22:57 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2021-10-28 18:19:35 +02:00
|
|
|
|
|
|
|
for (uint i = 0; i < area->nbPages; i++) {
|
|
|
|
pageUnmap(area->startAddr + i * PAGE_SIZE);
|
2021-10-26 22:29:51 +02:00
|
|
|
}
|
2021-10-28 18:19:35 +02:00
|
|
|
|
2021-02-10 23:22:57 +01:00
|
|
|
list_delete(usedArea, area);
|
2021-08-19 16:44:47 +02:00
|
|
|
insertSorted(&freeArea, area);
|
2021-02-10 23:22:57 +01:00
|
|
|
|
|
|
|
if (area->prev)
|
2021-11-12 10:19:43 +01:00
|
|
|
areaMergeFreeArea(area->prev, &area);
|
2021-02-10 23:22:57 +01:00
|
|
|
|
2021-11-13 08:31:05 +01:00
|
|
|
if (area && area->next)
|
2021-11-12 10:19:43 +01:00
|
|
|
areaMergeFreeArea(area, &(area->next));
|
2021-02-10 23:22:57 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|