65 lines
1.7 KiB
C
65 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);
|
||
|
}
|