smol-gilbraltar/kernel/pager.c
2024-12-23 23:44:47 +01:00

64 lines
1.7 KiB
C

#include <assert.h>
#include <log.h>
#include <spinlock.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <sysconfig.h>
#define FREE_PAGE_MAGIC 0x50474d43
#define PAGE_MASK (PAGE_SIZE - 1)
struct free_page {
uint32_t magic;
struct free_page *next;
};
static uint8_t *pager_next = 0;
static uint8_t *pager_limit = 0;
static struct free_page *free_list = 0;
static uint32_t spinlock = 0;
void gilbraltar_pager_init(uintptr_t base, size_t size) {
pager_next = (uint8_t *)((base + PAGE_SIZE - 1) & ~PAGE_MASK);
pager_limit = (uint8_t *)((base + size) & ~PAGE_MASK);
}
size_t gilbraltar_pager_free_space(void) { return (pager_limit - pager_next); }
void *gilbraltar_palloc(void) {
assert(pager_next != 0);
gilbraltar_spinlock_acquire(IRQ, &spinlock);
gilbraltar_log(DEBUG, "Allocate a new page (actual: %08lx)\r\n",
(uintptr_t)pager_next);
struct free_page *free_page;
if ((free_page = free_list) != 0) {
assert(free_page->magic == FREE_PAGE_MAGIC);
free_list = free_page->next;
free_page->magic = 0;
} else {
free_page = (struct free_page *)pager_next;
pager_next += PAGE_SIZE;
if (pager_next > pager_limit) {
gilbraltar_spinlock_release(IRQ, &spinlock);
gilbraltar_log(ERROR, "Out of page.\r\n");
abort();
}
}
gilbraltar_log(DEBUG, "New page @ %08lx.\r\n", (uintptr_t)free_page);
gilbraltar_spinlock_release(IRQ, &spinlock);
return (free_page);
}
void gilbraltar_pager_free(void *page) {
struct free_page *free_page = (struct free_page *)page;
gilbraltar_spinlock_acquire(IRQ, &spinlock);
free_page->magic = FREE_PAGE_MAGIC;
free_page->next = free_list;
free_list = free_page;
gilbraltar_spinlock_release(IRQ, &spinlock);
}