pmm: full rewrite

I've decided to do a rewrite on it due to some plans that would make refcounting physical pages nescessary among other things. now instead of a bitmap it uses a list of pages with each physical page having a page_t associated with it
This commit is contained in:
Matheus
2023-07-29 17:14:41 -03:00
parent 8ca2360991
commit 55fc1b7026
11 changed files with 267 additions and 179 deletions
+8 -8
View File
@@ -68,7 +68,7 @@ static bool add_page(pagetableptr_t top, void *vaddr, uint64_t entry, int depth)
uint64_t *pdpt = next(pml4[pml4offset]);
if (pdpt == NULL) {
pdpt = pmm_alloc(1, PMM_SECTION_DEFAULT);
pdpt = pmm_allocpage(PMM_SECTION_DEFAULT);
if (pdpt == NULL)
return false;
pml4[pml4offset] = (uint64_t)pdpt | INTERMEDIATE_FLAGS;
@@ -83,7 +83,7 @@ static bool add_page(pagetableptr_t top, void *vaddr, uint64_t entry, int depth)
uint64_t *pd = next(pdpt[pdptoffset]);
if (pd == NULL) {
pd = pmm_alloc(1, PMM_SECTION_DEFAULT);
pd = pmm_allocpage(PMM_SECTION_DEFAULT);
if (pd == NULL)
return false;
pdpt[pdptoffset] = (uint64_t)pd | INTERMEDIATE_FLAGS;
@@ -98,7 +98,7 @@ static bool add_page(pagetableptr_t top, void *vaddr, uint64_t entry, int depth)
uint64_t *pt = next(pd[pdoffset]);
if (pt == NULL) {
pt = pmm_alloc(1, PMM_SECTION_DEFAULT);
pt = pmm_allocpage(PMM_SECTION_DEFAULT);
if (pt == NULL)
return false;
pd[pdoffset] = (uint64_t)pt | INTERMEDIATE_FLAGS;
@@ -120,13 +120,13 @@ static void destroy(uint64_t *table, int depth) {
if (depth > 0)
destroy(MAKE_HHDM(addr), depth - 1);
pmm_free(addr, 1);
pmm_release(addr);
}
}
void arch_mmu_destroytable(pagetableptr_t table) {
destroy(MAKE_HHDM(table), 3);
pmm_free(table, 1);
pmm_release(table);
}
bool arch_mmu_map(pagetableptr_t table, void *paddr, void *vaddr, mmuflags_t flags) {
@@ -170,7 +170,7 @@ void arch_mmu_switch(pagetableptr_t table) {
static pagetableptr_t template;
pagetableptr_t arch_mmu_newtable() {
pagetableptr_t table = pmm_alloc(1, PMM_SECTION_DEFAULT);
pagetableptr_t table = pmm_allocpage(PMM_SECTION_DEFAULT);
if (table == NULL)
return NULL;
memcpy(MAKE_HHDM(table), template, PAGE_SIZE);
@@ -227,13 +227,13 @@ static void pfisr(isr_t *self, context_t *ctx) {
}
void arch_mmu_init() {
template = pmm_alloc(1, PMM_SECTION_DEFAULT);
template = pmm_allocpage(PMM_SECTION_DEFAULT);
__assert(template);
template = MAKE_HHDM(template);
memset(template, 0, PAGE_SIZE);
for (int i = 256; i < 512; ++i) {
uint64_t *entry = pmm_alloc(1, PMM_SECTION_DEFAULT);
uint64_t *entry = pmm_allocpage(PMM_SECTION_DEFAULT);
__assert(entry);
memset(MAKE_HHDM(entry), 0, PAGE_SIZE);
template[i] = (uint64_t)entry | INTERMEDIATE_FLAGS;
+1 -1
View File
@@ -86,7 +86,7 @@ static char *args[] = {
"fds %p nfds %d timeout %d", // poll
"time %p remaining %p", // nanosleep
"fd %d size %lu", // ftruncate
"backing %s mountpoint %s fs %s flags %d data %p" // mount
"backing %p mountpoint %s fs %s flags %d data %p" // mount
};
#endif
+4 -4
View File
@@ -1435,12 +1435,12 @@ static int ext2_symlink(vnode_t *vnode, char *name, vattr_t *attr, char *path, c
#define MMAPTMPFLAGS (ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_NOEXEC | ARCH_MMU_FLAGS_WRITE)
static int ext2_mmap(vnode_t *node, void *addr, uintmax_t offset, int flags, cred_t *cred) {
void *paddr = pmm_alloc(1, PMM_SECTION_DEFAULT);
void *paddr = pmm_allocpage(PMM_SECTION_DEFAULT);
if (paddr == NULL)
return ENOMEM;
if (arch_mmu_map(_cpu()->vmmctx->pagetable, paddr, addr, MMAPTMPFLAGS) == false) {
pmm_free(paddr, 1);
pmm_release(paddr);
return ENOMEM;
}
@@ -1448,7 +1448,7 @@ static int ext2_mmap(vnode_t *node, void *addr, uintmax_t offset, int flags, cre
int e = ext2_read(node, addr, PAGE_SIZE, offset, flags, &readc, cred);
if (e) {
arch_mmu_unmap(_cpu()->vmmctx->pagetable, addr);
pmm_free(paddr, 1);
pmm_release(paddr);
return e;
}
@@ -1469,7 +1469,7 @@ static int ext2_munmap(vnode_t *node, void *addr, uintmax_t offset, int flags, c
void *paddr = arch_mmu_getphysical(_cpu()->vmmctx->pagetable, addr);
__assert(paddr);
arch_mmu_unmap(_cpu()->vmmctx->pagetable, addr);
pmm_free(paddr, 1);
pmm_release(paddr);
return 0;
}
+2 -2
View File
@@ -126,7 +126,7 @@ void initrd_unpack() {
for (;;) {
if (cleanupbytespassed >= PAGE_SIZE) {
size_t pagec = cleanupbytespassed / PAGE_SIZE;
pmm_free(FROM_HHDM(cleanupptr), pagec);
pmm_makefree(FROM_HHDM(cleanupptr), pagec);
cleanupptr = (void *)((uintptr_t)cleanupptr + ROUND_DOWN(cleanupbytespassed, PAGE_SIZE));
cleanupbytespassed %= PAGE_SIZE;
}
@@ -174,5 +174,5 @@ void initrd_unpack() {
}
// free remaining pages to be freed
pmm_free(FROM_HHDM(cleanupptr), ROUND_UP(cleanupbytespassed, PAGE_SIZE) / PAGE_SIZE);
pmm_makefree(FROM_HHDM(cleanupptr), ROUND_UP(cleanupbytespassed, PAGE_SIZE) / PAGE_SIZE);
}
+4 -4
View File
@@ -392,12 +392,12 @@ static int tmpfs_readlink(vnode_t *node, char **link, cred_t *cred) {
#define MMAPTMPFLAGS (ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_NOEXEC | ARCH_MMU_FLAGS_WRITE)
static int tmpfs_mmap(vnode_t *node, void *addr, uintmax_t offset, int flags, cred_t *cred) {
void *paddr = pmm_alloc(1, PMM_SECTION_DEFAULT);
void *paddr = pmm_allocpage(PMM_SECTION_DEFAULT);
if (paddr == NULL)
return ENOMEM;
if (arch_mmu_map(_cpu()->vmmctx->pagetable, paddr, addr, MMAPTMPFLAGS) == false) {
pmm_free(paddr, 1);
pmm_release(paddr);
return ENOMEM;
}
@@ -405,7 +405,7 @@ static int tmpfs_mmap(vnode_t *node, void *addr, uintmax_t offset, int flags, cr
int e = tmpfs_read(node, addr, PAGE_SIZE, offset, flags, &readc, cred);
if (e) {
arch_mmu_unmap(_cpu()->vmmctx->pagetable, addr);
pmm_free(paddr, 1);
pmm_release(paddr);
return e;
}
@@ -426,7 +426,7 @@ static int tmpfs_munmap(vnode_t *node, void *addr, uintmax_t offset, int flags,
void *paddr = arch_mmu_getphysical(_cpu()->vmmctx->pagetable, addr);
__assert(paddr);
arch_mmu_unmap(_cpu()->vmmctx->pagetable, addr);
pmm_free(paddr, 1);
pmm_release(paddr);
return 0;
}
+31 -3
View File
@@ -9,9 +9,37 @@
#define PMM_SECTION_4GB 1
#define PMM_SECTION_DEFAULT 2
void *pmm_alloc(size_t count, int flags);
void pmm_free(void *addr, size_t count);
void pmm_init();
#define PAGE_FLAGS_FREE 1
typedef struct page_t {
struct vnode_t *backing;
uintmax_t offset;
struct page_t *hashnext;
struct page_t *hashprev;
struct page_t *vnodenext;
struct page_t *vnodeprev;
union {
struct {
struct page_t *freenext;
struct page_t *freeprev;
};
struct {
struct page_t *writenext;
struct page_t *writeprev;
};
};
uintmax_t refcount;
int flags;
} page_t;
void *pmm_allocpage(int section);
page_t *pmm_getpage(void *addr);
void pmm_hold(void *addr);
void pmm_release(void *addr);
void pmm_makefree(void *address, size_t count);
void *pmm_alloc(size_t size, int section);
void pmm_free(void *addr, size_t size);
void pmm_init();
extern uintptr_t hhdmbase;
+15 -12
View File
@@ -233,7 +233,7 @@ typedef struct {
int phase;
} queuedesc_t;
#define QUEUEPAIR_ENTRY_COUNT 256
#define QUEUEPAIR_ENTRY_COUNT (PAGE_SIZE / sizeof(subentry_t))
typedef struct {
queuedesc_t submission;
@@ -350,7 +350,7 @@ static int identify(nvmecontroller_t *controller, void *buffer, int what, int na
entrypair_t pair = {0};
PAIR_INIT(&pair, SUB_DW0_OPCODE_IDENTIFY, SUB_DW0_UNFUSED, SUB_DW0_PRP, 0);
pair.sub.datapointer[0] = (uint64_t)pmm_alloc(1, PMM_SECTION_DEFAULT);
pair.sub.datapointer[0] = (uint64_t)pmm_allocpage(PMM_SECTION_DEFAULT);
if (pair.sub.datapointer[0] == 0)
return ENOMEM;
@@ -519,30 +519,33 @@ static int iowrite(nvmenamespace_t *namespace, uint64_t prp[2], uint64_t lba, ui
static int rwblocks(nvmenamespace_t *namespace, void *buffer, uintmax_t lba, size_t count, bool write, bool pagealignedbuffer) {
// TODO this is pretty inefficient and will be replaced later
__assert(namespace->blocksize < PAGE_SIZE * 2);
void *phys = pmm_alloc(2, PMM_SECTION_DEFAULT);
if (phys == NULL)
return ENOMEM;
__assert(namespace->blocksize <= PAGE_SIZE);
uint64_t prp[2] = {(uint64_t)phys, (uint64_t)phys + PAGE_SIZE};
uint64_t prp[2] = {(uint64_t)pmm_allocpage(PMM_SECTION_DEFAULT), 0};
int err = 0;
if (prp[0] == 0)
goto cleanup;
for (int i = 0; i < count; ++i) {
void *bufferp = (void *)((uintptr_t)buffer + i * namespace->blocksize);
if (write)
memcpy(MAKE_HHDM(phys), bufferp, namespace->blocksize);
if (write) {
memcpy(MAKE_HHDM(prp[0]), bufferp, namespace->blocksize);
}
err = write ? iowrite(namespace, prp, lba + i, 1) : ioread(namespace, prp, lba + i, 1);
if (err)
goto cleanup;
if (!write)
memcpy(bufferp, MAKE_HHDM(phys), namespace->blocksize);
if (!write) {
memcpy(bufferp, MAKE_HHDM(prp[0]), namespace->blocksize);
}
}
cleanup:
pmm_free(phys, 2);
if (prp[0])
pmm_release((void *)prp[0]);
return err;
}
+3 -3
View File
@@ -129,14 +129,14 @@ static int mmap(int minor, void *addr, uintmax_t offset, int flags) {
return arch_mmu_map(_cpu()->vmmctx->pagetable, FROM_HHDM((void *)((uintptr_t)fbs[minor]->address + offset)), addr, vnodeflagstommuflags(flags)) ? 0 : ENOMEM;
} else {
size_t size = offset + PAGE_SIZE < end ? PAGE_SIZE : end - offset;
paddr = pmm_alloc(1, PMM_SECTION_DEFAULT);
paddr = pmm_allocpage(PMM_SECTION_DEFAULT);
if (paddr == NULL)
return ENOMEM;
memcpy(MAKE_HHDM(paddr), (void *)((uintptr_t)fbs[minor]->address + offset), size);
if (arch_mmu_map(_cpu()->vmmctx->pagetable, paddr, addr, vnodeflagstommuflags(flags)) == false) {
pmm_free(paddr, 1);
pmm_release(paddr);
return ENOMEM;
}
@@ -148,7 +148,7 @@ static int munmap(int minor, void *addr, uintmax_t offset, int flags) {
void *phys = arch_mmu_getphysical(_cpu()->vmmctx->pagetable, addr);
arch_mmu_unmap(_cpu()->vmmctx->pagetable, addr);
if ((flags & V_FFLAGS_SHARED) == 0) {
pmm_free(phys, 1);
pmm_release(phys);
}
return 0;
+3
View File
@@ -0,0 +1,3 @@
void pgcache_init() {
}
+190 -136
View File
@@ -4,22 +4,30 @@
#include <string.h>
#include <arch/mmu.h>
#include <spinlock.h>
#include <util.h>
uintptr_t hhdmbase;
static size_t memorysize;
static size_t physicalpagecount;
static size_t used;
static size_t pagecount;
static spinlock_t freelistlock;
static page_t *freelists[PMM_SECTION_COUNT];
static page_t *standbylists[PMM_SECTION_COUNT];
typedef struct {
spinlock_t lock;
uintmax_t base;
uintmax_t top;
uintmax_t baseid;
uintmax_t topid;
uintmax_t searchstart;
} bmsection_t;
} section_t;
static bmsection_t bmsections[PMM_SECTION_COUNT];
#define TOP_1MB (0x100000 / PAGE_SIZE)
#define TOP_4GB ((uint64_t)0x100000000 / PAGE_SIZE)
static uint64_t *bitmap;
static section_t sections[PMM_SECTION_COUNT] = {
{0, TOP_1MB, 0},
{TOP_1MB, TOP_4GB, TOP_1MB},
{TOP_4GB, 0xffffffffffffffffl, TOP_4GB}
};
static volatile struct limine_hhdm_request hhdmreq = {
.id = LIMINE_HHDM_REQUEST,
@@ -31,169 +39,215 @@ volatile struct limine_memmap_request pmm_liminemap = {
.revision = 0
};
static inline void bmset(void *addr, uint64_t v) {
uintmax_t page = (uintptr_t)addr / PAGE_SIZE;
uintmax_t entry = page / 64;
uintmax_t offset = page % 64;
static page_t* pages;
uint64_t entryval = bitmap[entry];
entryval &= ~((uint64_t)1 << offset);
entryval |= v << offset;
bitmap[entry] = entryval;
#define PAGE_GETID(page) (((uintptr_t)(page) - (uintptr_t)pages) / sizeof(page_t))
#define PAGE_BOUNDARYCHECK(pageid) \
__assert((pageid) * PAGE_SIZE < (uintptr_t)pages || (pageid) * PAGE_SIZE >= (uintptr_t)&pages[pagecount])
static void insertinfreelist(page_t *page) {
uintmax_t pageid = PAGE_GETID(page);
PAGE_BOUNDARYCHECK(pageid);
struct page_t **list;
int section;
if (pageid < TOP_1MB)
section = PMM_SECTION_1MB;
else if (pageid < TOP_4GB)
section = PMM_SECTION_4GB;
else
section = PMM_SECTION_DEFAULT;
list = page->backing ? &standbylists[section] : &freelists[section];
if (sections[section].searchstart > pageid)
sections[section].searchstart = pageid;
page->freenext = *list;
page->freeprev = NULL;
*list = page;
if (page->freenext)
page->freenext->freeprev = page;
}
static inline bool bmget(void *addr) {
uintmax_t page = (uintptr_t)addr / PAGE_SIZE;
uintmax_t entry = page / 64;
uintmax_t offset = page % 64;
static void removefromfreelist(page_t *page) {
uintmax_t pageid = PAGE_GETID(page);
PAGE_BOUNDARYCHECK(pageid);
struct page_t **list;
uint64_t entryval = bitmap[entry];
entryval &= ((uint64_t)1 << offset);
return entryval;
int section;
if (pageid < TOP_1MB)
section = PMM_SECTION_1MB;
else if (pageid < TOP_4GB)
section = PMM_SECTION_4GB;
else
section = PMM_SECTION_DEFAULT;
list = page->backing ? &standbylists[section] : &freelists[section];
if (page->freeprev)
page->freeprev->freenext = page->freenext;
else
*list = page->freenext;
if (page->freenext)
page->freenext->freeprev = page->freeprev;
}
static uintmax_t getfreearea(bmsection_t *section, size_t size) {
uintmax_t result = 0;
uintmax_t found = 0;
void pmm_hold(void *addr) {
page_t *page = &pages[((uintptr_t)addr / PAGE_SIZE)];
__atomic_add_fetch(&page->refcount, 1, __ATOMIC_SEQ_CST);
}
for (uintmax_t search = section->searchstart; search < section->top && found < size; ++search) {
uintmax_t entry = search / 64;
uintmax_t offset = search % 64;
void pmm_release(void *addr) {
page_t *page = &pages[(uintptr_t)addr / PAGE_SIZE];
__assert(page->refcount != 0);
if (bitmap[entry] == 0) {
search += 63 - offset; // 63 because search gets incremented on continue
result = 0;
found = 0;
continue;
}
if (((bitmap[entry] >> offset) & 1) == 0) {
found = 0;
result = 0;
continue;
}
if (found == 0)
result = search;
++found;
uintmax_t newrefcount = __atomic_sub_fetch(&page->refcount, 1, __ATOMIC_SEQ_CST);
if (newrefcount == 0) {
spinlock_acquire(&freelistlock);
insertinfreelist(page);
if (page->backing == NULL)
page->flags |= PAGE_FLAGS_FREE;
spinlock_release(&freelistlock);
}
return result;
}
static inline void initsection(int section, uintmax_t base, uintmax_t top) {
bmsections[section] = (bmsection_t){
.base = base,
.top = top,
.searchstart = base
};
SPINLOCK_INIT(bmsections[section].lock);
static void doalloc(page_t *page) {
__assert(page->refcount == 0);
memset(page, 0, sizeof(page_t));
page->refcount = 1;
page->flags &= ~PAGE_FLAGS_FREE;
}
void *pmm_alloc(size_t size, int section) {
void *pmm_allocpage(int section) {
spinlock_acquire(&freelistlock);
page_t *page = NULL;
for (int i = section; i >= 0; --i) {
spinlock_acquire(&bmsections[i].lock);
uintmax_t page = getfreearea(&bmsections[i], size);
page = freelists[i];
if (page) {
if (page == bmsections[i].searchstart)
bmsections[i].searchstart += size;
for (size_t j = 0; j < size; ++j)
bmset((void *)((page + j) * PAGE_SIZE), 0);
spinlock_release(&bmsections[i].lock);
__atomic_add_fetch(&used, 1, __ATOMIC_SEQ_CST);
return (void *)(page * PAGE_SIZE);
}
spinlock_release(&bmsections[i].lock);
}
return NULL;
}
void pmm_free(void *addr, size_t size) {
uintmax_t page = (uintptr_t)addr / PAGE_SIZE;
for (int i = 0; i < PMM_SECTION_COUNT; ++i) {
if (page >= bmsections[i].base && page < bmsections[i].top) {
spinlock_acquire(&bmsections[i].lock);
if ((uintptr_t)addr / PAGE_SIZE < bmsections[i].searchstart)
bmsections[i].searchstart = (uintptr_t)addr / PAGE_SIZE;
for (uintmax_t j = 0; j < size; ++j) {
__assert(bmget((void *)((page + j) * PAGE_SIZE)) == false);
bmset((void *)((page + j) * PAGE_SIZE), 1);
}
spinlock_release(&bmsections[i].lock);
__atomic_sub_fetch(&used, 1, __ATOMIC_SEQ_CST);
return;
removefromfreelist(page);
break;
}
}
// TODO get page from standby list and call to remove from cache
spinlock_release(&freelistlock);
void *address = NULL;
if (page) {
address = (void *)(PAGE_GETID(page) * PAGE_SIZE);
doalloc(page);
}
return address;
}
void pmm_getinfo(size_t *pages, size_t *usedpages) {
if (pages)
*pages = physicalpagecount;
if (usedpages)
*usedpages = used;
void pmm_makefree(void *address, size_t count) {
memorysize += PAGE_SIZE * count;
__assert(((uintptr_t)address % PAGE_SIZE) == 0);
uintmax_t baseid = (uintptr_t)address / PAGE_SIZE;
for (int i = 0; i < count; ++i) {
uintmax_t pageid = baseid + i;
PAGE_BOUNDARYCHECK(pageid);
page_t *page = &pages[pageid];
insertinfreelist(page);
}
}
#define TOP_1MB (0x100000 / PAGE_SIZE)
#define TOP_4GB ((uint64_t)0x100000000 / PAGE_SIZE)
void pmm_init() {
__assert(hhdmreq.response);
hhdmbase = hhdmreq.response->offset;
__assert(pmm_liminemap.response);
uintmax_t topofmemory = 0;
// get size of memory and print memory map
printf("memory map:\n");
// get size of memory, top of usable memory, biggest section and print memory map
size_t top = 0;
struct limine_memmap_entry *biggest = NULL;
printf("pmm: ranges:\n");
for (size_t i = 0; i < pmm_liminemap.response->entry_count; ++i) {
struct limine_memmap_entry *e = pmm_liminemap.response->entries[i];
printf("%016p -> %016p: %d\n", e->base, e->base + e->length, e->type);
printf("pmm: %016p -> %016p: %d\n", e->base, e->base + e->length, e->type);
if (e->type == LIMINE_MEMMAP_USABLE || e->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE) {
size_t sectiontop = e->base + e->length;
if (sectiontop > top)
top = sectiontop;
}
if (e->type == LIMINE_MEMMAP_USABLE) {
topofmemory = e->base + e->length;
if (biggest == NULL || e->length > biggest->length)
biggest = e;
memorysize += e->length;
}
}
physicalpagecount = topofmemory / PAGE_SIZE;
pages = MAKE_HHDM((page_t *)biggest->base);
pagecount = ROUND_UP(top, PAGE_SIZE) / PAGE_SIZE;
memset(pages, 0, pagecount / sizeof(page_t));
printf("pmm: %d pages used for page list\n", ROUND_UP(pagecount * sizeof(page_t), PAGE_SIZE) / PAGE_SIZE);
size_t bitmapsize = physicalpagecount / 8;
// find out where to put the bitmap
for (uintmax_t i = 0; i < pmm_liminemap.response->entry_count; ++i) {
// place pages in free lists
for (size_t i = 0; i < pmm_liminemap.response->entry_count; ++i) {
struct limine_memmap_entry *e = pmm_liminemap.response->entries[i];
if (e->type == LIMINE_MEMMAP_USABLE && e->length >= bitmapsize)
bitmap = (uint64_t *)e->base;
}
__assert(bitmap);
memset(bitmap, 0, bitmapsize);
// set free pages
for (uintmax_t i = 0; i < pmm_liminemap.response->entry_count; ++i) {
struct limine_memmap_entry *e = pmm_liminemap.response->entries[i];
if (e->type != LIMINE_MEMMAP_USABLE)
continue;
for (uintmax_t offset = 0; offset < e->length; offset += PAGE_SIZE)
bmset((void *)(e->base + offset), 1);
if (e->type == LIMINE_MEMMAP_USABLE) {
int firstusablepage = e == biggest ? ROUND_UP(e->base + pagecount * sizeof(page_t), PAGE_SIZE) / PAGE_SIZE : e->base / PAGE_SIZE;
for (int i = firstusablepage; i < (e->base + e->length) / PAGE_SIZE; ++i) {
pages[i].flags |= PAGE_FLAGS_FREE;
insertinfreelist(&pages[i]);
}
}
}
// set bitmap as used
for (uintmax_t offset = 0; offset < bitmapsize; offset += PAGE_SIZE)
bmset((void *)((uintptr_t)bitmap + offset), 0);
// prepare sections
// for all cases this section will always be present so hardcode its values (otherwise the system wouldn't even get here)
initsection(PMM_SECTION_1MB, 1, TOP_1MB);
initsection(PMM_SECTION_4GB, TOP_1MB, physicalpagecount > TOP_4GB ? TOP_4GB : physicalpagecount);
initsection(PMM_SECTION_DEFAULT, TOP_4GB, physicalpagecount > TOP_4GB ? physicalpagecount : TOP_4GB);
bitmap = MAKE_HHDM(bitmap);
SPINLOCK_INIT(freelistlock);
}
void *pmm_alloc(size_t size, int section) {
__assert(size);
// pmm_allocpage is more suited for single page allocations, so use that instead
if (size == 1)
return pmm_allocpage(section);
spinlock_acquire(&freelistlock);
uintmax_t page = 0;
size_t found = 0;
for (; section >= 0; --section) {
for (page = sections[section].searchstart; page < sections[section].topid; ++page) {
if (page >= pagecount)
break;
if (pages[page].flags & PAGE_FLAGS_FREE) {
++found;
} else
found = 0;
if (found == size)
goto gotpages;
}
found = 0;
}
gotpages:
void *addr = NULL;
if (found == size) {
page = page - (found - 1);
addr = (void *)(page * PAGE_SIZE);
for (int i = 0; i < size; ++i) {
removefromfreelist(&pages[page + i]);
doalloc(&pages[page + i]);
}
}
spinlock_release(&freelistlock);
return addr;
}
void pmm_free(void *addr, size_t size) {
__assert(size);
// release multiple pages at once
__assert(((uintptr_t)addr % PAGE_SIZE) == 0);
for (int i = 0; i < size; ++i)
pmm_release((void *)((uintptr_t)addr + PAGE_SIZE * i));
}
+6 -6
View File
@@ -10,7 +10,7 @@
#define RANGE_TOP(x) (void *)((uintptr_t)x->start + x->size)
static vmmcache_t *newcache() {
vmmcache_t *ptr = pmm_alloc(1, PMM_SECTION_DEFAULT);
vmmcache_t *ptr = pmm_allocpage(PMM_SECTION_DEFAULT);
if (ptr == NULL)
return NULL;
ptr = MAKE_HHDM(ptr);
@@ -221,7 +221,7 @@ static void destroyrange(vmmrange_t *range, uintmax_t _offset, size_t size, int
if ((range->flags & VMM_FLAGS_FILE) && (range->flags & VMM_FLAGS_SHARED) && (flags & VMM_DESTROY_FLAGS_NOSYNC) == 0) {
__assert(VOP_MUNMAP(range->vnode, vaddr, range->offset + offset, mmuflagstovnodeflags(range->mmuflags) | (range->flags & VMM_FLAGS_SHARED ? V_FFLAGS_SHARED : 0), cred) == 0);
} else {
pmm_free(physical, 1);
pmm_release(physical);
arch_mmu_unmap(_cpu()->vmmctx->pagetable, vaddr);
}
}
@@ -330,7 +330,7 @@ bool vmm_pagefault(void *addr, bool user, int actions) {
__assert(VOP_MMAP(range->vnode, addr, range->offset + mapoffset, mmuflagstovnodeflags(range->mmuflags) | (range->flags & VMM_FLAGS_SHARED ? V_FFLAGS_SHARED : 0), cred) == 0);
status = true;
} else {
void *paddr = pmm_alloc(1, PMM_SECTION_DEFAULT);
void *paddr = pmm_allocpage(PMM_SECTION_DEFAULT);
__assert(paddr); // XXX handle these better than an assert once there are signals and such
__assert(arch_mmu_map(_cpu()->vmmctx->pagetable, paddr, addr, range->mmuflags));
memset(MAKE_HHDM(paddr), 0, PAGE_SIZE);
@@ -399,7 +399,7 @@ void *vmm_map(void *addr, volatile size_t size, int flags, mmuflags_t mmuflags,
} else if (flags & VMM_FLAGS_ALLOCATE) {
// allocate to virtual memory
for (uintmax_t i = 0; i < size; i += PAGE_SIZE) {
void *allocated = pmm_alloc(1, PMM_SECTION_DEFAULT);
void *allocated = pmm_allocpage(PMM_SECTION_DEFAULT);
if (allocated == NULL) {
retaddr = NULL;
goto cleanup;
@@ -411,7 +411,7 @@ void *vmm_map(void *addr, volatile size_t size, int flags, mmuflags_t mmuflags,
void *physical = arch_mmu_getphysical(_cpu()->vmmctx->pagetable, virt);
if (physical) {
pmm_free(physical, 1);
pmm_release(physical);
arch_mmu_unmap(_cpu()->vmmctx->pagetable, virt);
}
}
@@ -529,7 +529,7 @@ vmmcontext_t *vmm_fork(vmmcontext_t *oldcontext) {
if (phys == NULL)
continue;
void *palloc = pmm_alloc(1, PMM_SECTION_DEFAULT);
void *palloc = pmm_allocpage(PMM_SECTION_DEFAULT);
if (palloc == NULL)
goto error;