1
0
Fork 0
mirror of https://git.stationery.faith/corn/corn.git synced 2025-04-11 06:57:26 +00:00
corn/src/memory/physalloc.c

234 lines
5.1 KiB
C

#include <memory.h>
#include <stdint.h>
#include <lib.h>
#include <stddef.h>
#define MEMORY_INTERNAL
#include <memory/physalloc.h>
#include <memory/virtalloc.h>
extern char kernel_start;
extern char kernel_end;
#define kaddr(addr) ((uintptr_t)(&addr))
// between memory_start and kernel_start will be the bitmap
static uintptr_t memory_start = 0;
struct memory_area {
uint64_t len;
uintptr_t addr;
};
static uint64_t *bitmap;
static uint64_t total_memory;
static uint64_t free_memory;
static uint64_t page_count;
static uint64_t segment_count;
struct memory_area *page_start;
static int n_pages(const struct memory_area *m) {
return m->len / PAGE_SIZE;
}
static void *page_at(int i) {
int cur_page = 0;
for (uint64_t idx = 0; idx < segment_count; idx++) {
const struct memory_area *m = page_start;
int pages = n_pages(m);
if (i - cur_page < pages) {
return (void *) (m->addr + (PAGE_SIZE * (i - cur_page)));
}
cur_page += pages;
}
return NULL;
}
static long page_idx(void *page) {
uintptr_t addr = (uintptr_t) page;
int cur_page = 0;
for (uint64_t idx = 0; idx < segment_count; idx++) {
const struct memory_area *m = page_start;
if ((uintptr_t) m + m->len > addr) {
return cur_page + ((addr - m->addr) / PAGE_SIZE);
}
cur_page += n_pages(m);
}
return -1;
}
static inline bool bitmap_get(int i) {
return (bitmap[i / 64] >> i % 64) & 1;
}
static inline void bitmap_set(int i, bool v) {
if (v)
free_memory -= PAGE_SIZE;
else
free_memory += PAGE_SIZE;
int idx = i / 64;
bitmap[idx] &= ~(1 << i % 64);
bitmap[idx] |= (v << i % 64);
}
void *alloc_phys_page(void) {
return alloc_phys_pages(1);
}
void *alloc_phys_pages(int pages) {
if (pages < 1) return NULL;
int n_contiguous = 0;
int free_region_start = 0;
for (uint64_t i = 0; i < page_count; i++) {
bool free = !bitmap_get(i);
if (free) {
if (n_contiguous == 0) free_region_start = i;
n_contiguous++;
if (n_contiguous == pages) {
for (int j = 0; j < pages; j++)
bitmap_set(free_region_start + j, true);
return page_at(free_region_start);
}
} else n_contiguous = 0;
}
return NULL;
}
void free_phys_page(void *ptr) {
free_phys_pages(ptr, 1);
}
void free_phys_pages(void *ptr, int pages) {
long idx = page_idx(ptr);
if (idx == -1) return;
for (int i = 0; i < pages; i++)
bitmap_set(idx + pages, false);
}
static bool segment_invalid(const struct memory_segment *segment) {
if (segment->type != 1) return true;
if (segment->addr < kaddr(kernel_start)) return true;
if (segment->addr + segment->len < memory_start) return true;
if (segment->addr + segment->len < kaddr(kernel_start)) return true;
return false;
}
static struct memory_area segment_to_area(const struct memory_segment *segment) {
uint64_t length = segment->len;
uintptr_t addr = segment->addr;
uintptr_t start;
if (memory_start)
start = memory_start;
else
start = kaddr(kernel_end);
if (segment->addr < start) {
addr = start;
length -= addr - segment->addr;
} else {
addr = segment->addr;
}
struct memory_area temp;
temp.len = length;
temp.addr = addr;
return temp;
}
static uintptr_t page_align(uintptr_t ptr) {
return (ptr + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE;
}
void memory_init(struct memory_map *map) {
memory_lock();
virtaddr_init();
bitmap = NULL;
total_memory = 0;
free_memory = 0;
page_count = 0;
page_start = NULL;
segment_count = 0;
for (uint32_t i = 0; i < map->entry_count; i++) {
struct memory_segment *segment = &map->entries[i];
if (segment_invalid(segment))
continue;
struct memory_area temp = segment_to_area(segment);
page_count += n_pages(&temp);
segment_count++;
}
long bitmap_pages = (page_count / 64 / PAGE_SIZE) + 1;
long bitmap_size = bitmap_pages * PAGE_SIZE;
bitmap = (uint64_t *) page_align(kaddr(kernel_end));
long page_area_size = segment_count * sizeof(struct memory_area);
char *page_area_addr = (char *)bitmap + bitmap_size;
page_area_addr = (char *) page_align((uintptr_t) page_area_addr);
memory_start = page_align((uintptr_t)page_area_addr + page_area_size);
bitmap = mmap(bitmap, bitmap_size);
memset(bitmap, 0, bitmap_size);
page_area_addr = mmap(page_area_addr, page_area_size);
memset(page_area_addr, 0, page_area_size);
page_start = (struct memory_area *) page_area_addr;
struct memory_area *area = page_start;
kprintf("MEMORY MAP\n");
for (uint32_t i = 0; i < map->entry_count; i++) {
struct memory_segment *segment = &map->entries[i];
if (segment_invalid(segment))
continue;
kprintf("addr: 0x%16p\tlen: %ld\n", (void *)segment->addr, segment->len);
struct memory_area temp = segment_to_area(segment);
*area = temp;
area++;
}
total_memory = page_count * PAGE_SIZE;
page_count -= bitmap_pages;
free_memory = page_count * PAGE_SIZE;
char buf[20];
kprintf("\nMEMORY USAGE\n");
kprintf("mem total: %s\n", btoa(memory_total(), buf));
kprintf("mem free: %s\n", btoa(memory_free(), buf));
kprintf("mem used: %s\n\n", btoa(memory_used(), buf));
memory_unlock();
}
void *alloc_page(void) {
return alloc_pages(1);
}
uint64_t memory_total(void) {
return total_memory;
}
uint64_t memory_free(void) {
return free_memory;
}
uint64_t memory_used(void) {
return total_memory - free_memory;
}