mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
kernel: pmm
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <arch/gdt.h>
|
||||
#include <arch/idt.h>
|
||||
#include <kernel/term.h>
|
||||
#include <kernel/pmm.h>
|
||||
|
||||
static cpu_t bsp_cpu;
|
||||
|
||||
@@ -13,6 +14,7 @@ void kernel_entry() {
|
||||
arch_gdt_reload();
|
||||
arch_idt_setup();
|
||||
arch_idt_reload();
|
||||
pmm_init();
|
||||
term_init();
|
||||
__assert(!"kernel entry end");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef _PMM_H
|
||||
#define _PMM_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PMM_SECTION_COUNT 3
|
||||
#define PMM_SECTION_1MB 0
|
||||
#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();
|
||||
|
||||
extern uintptr_t hhdmbase;
|
||||
|
||||
#define MAKE_HHDM(x) (void *)((uintptr_t)x + hhdmbase)
|
||||
#define FROM_HHDM(x) (void *)((uintptr_t)x - hhdmbase)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,174 @@
|
||||
#include <kernel/pmm.h>
|
||||
#include <limine.h>
|
||||
#include <logging.h>
|
||||
#include <string.h>
|
||||
|
||||
uintptr_t hhdmbase;
|
||||
static size_t memorysize;
|
||||
static size_t physicalpagecount;
|
||||
|
||||
typedef struct {
|
||||
uintmax_t base;
|
||||
uintmax_t top;
|
||||
uintmax_t searchstart;
|
||||
} bmsection_t;
|
||||
|
||||
static bmsection_t bmsections[PMM_SECTION_COUNT];
|
||||
|
||||
static uint64_t *bitmap;
|
||||
|
||||
// TODO move to arch specific header
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
static volatile struct limine_hhdm_request hhdmreq = {
|
||||
.id = LIMINE_HHDM_REQUEST,
|
||||
.revision = 0
|
||||
};
|
||||
|
||||
volatile struct limine_memmap_request pmm_liminemap = {
|
||||
.id = LIMINE_MEMMAP_REQUEST,
|
||||
.revision = 0
|
||||
};
|
||||
|
||||
static inline void bmset(void *addr, int v) {
|
||||
uintmax_t page = (uintptr_t)addr / PAGE_SIZE;
|
||||
uintmax_t entry = page / 64;
|
||||
uintmax_t offset = page % 64;
|
||||
|
||||
uint64_t entryval = bitmap[entry];
|
||||
entryval &= ~((uint64_t)1 << offset);
|
||||
entryval |= v << offset;
|
||||
bitmap[entry] = entryval;
|
||||
}
|
||||
|
||||
static uintmax_t getfreearea(bmsection_t *section, size_t size) {
|
||||
uintmax_t result = 0;
|
||||
uintmax_t found = 0;
|
||||
|
||||
for (uintmax_t search = section->searchstart; search < section->top && found < size; ++search) {
|
||||
uintmax_t entry = search / 64;
|
||||
uintmax_t offset = search % 64;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void initsection(int section, uintmax_t base, uintmax_t top) {
|
||||
bmsections[section] = (bmsection_t){
|
||||
.base = base,
|
||||
.top = top,
|
||||
.searchstart = base
|
||||
};
|
||||
}
|
||||
|
||||
void *pmm_alloc(size_t size, int section) {
|
||||
for (int i = section; i >= 0; --i) {
|
||||
// TODO lock section
|
||||
uintmax_t page = getfreearea(&bmsections[i], size);
|
||||
|
||||
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);
|
||||
// TODO unlock
|
||||
return (void *)(page * PAGE_SIZE);
|
||||
}
|
||||
// TODO unlock section
|
||||
}
|
||||
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) {
|
||||
// TODO 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)
|
||||
bmset((void *)((page + j) * PAGE_SIZE), 1);
|
||||
|
||||
// TODO unlock
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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");
|
||||
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);
|
||||
if (e->type == LIMINE_MEMMAP_USABLE) {
|
||||
topofmemory = e->base + e->length;
|
||||
memorysize += e->length;
|
||||
}
|
||||
}
|
||||
|
||||
physicalpagecount = topofmemory / 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
Reference in New Issue
Block a user