Newer
Older
tree-os / src / kernel / memory / paging.c
#include <alloc.h>
#include <paging.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>

extern uintptr_t kernelEnd;

PageTablePointer *kernelPageTable;
PagePointer *kernelPages;
uint32_t *allocatedPages;
// uint32_t *freePageChunks; // todo: hierarchical structure to find a free page
// more quickly (make one bit an indicator weacher any
// page in the next layer is free) need to find a compromise between size and
// speed

void *getPage();

void identityMapPagesUntil(void *end) {
    void *currentAddress = (void *)0;
    while (currentAddress < end) {
        currentAddress = getPage();
    }
}

void enablePaging() {
    asm volatile("mov %%eax, %%cr3" : : "a"(kernelPageTable));
    asm volatile("mov %cr0, %eax");
    asm volatile("orl $0x80000000, %eax");
    asm volatile("mov %eax, %cr0");
}

void initializePaging() {
    void *currentPosition = (void *)((kernelEnd - 1) & ~0xFFF) + 0x1000;
    kernelPageTable = currentPosition;
    currentPosition += 0x4000;
    kernelPages = currentPosition;
    currentPosition += sizeof(uint32_t) * 1024 * 1024;
    allocatedPages = currentPosition;
    currentPosition +=
        sizeof(uint32_t) * 1024 * 1024 / 32; // 1024 tables with 1024 pages each
    for (int i = 0; i < 1024; i++) {
        kernelPageTable[i].present = 1;
        kernelPageTable[i].writable = 1;
        kernelPageTable[i].pagePointerAddress =
            (uint32_t)(uintptr_t)(kernelPages + 1024 * i) >> 12;
    }
    for (uint32_t i = 0; i < 0x100000; i++) {
        // mark all as inaccessible
        kernelPages[i].present = 0;
    }
    identityMapPagesUntil(currentPosition);
    enablePaging();
}

void allocatePage(uint32_t index32bit, uint8_t bit) {
    allocatedPages[index32bit] |= 1 << bit;
    uint32_t pageId = index32bit + bit;
    kernelPages[pageId].present = 1;
    kernelPages[pageId].writable = 1;
    kernelPages[pageId].pageId = pageId;
}

void *getPage() {
    // todo: add task handling etc.
    for (uint32_t i = 0; i < 0x100000; i += 32) {
        if (allocatedPages[i] == ~0) {
            continue;
        }
        for (uint8_t bit = 0; bit < 32; bit++) {
            if (allocatedPages[i] & (1 << bit)) {
                continue;
            }
            allocatePage(i, bit);
            return (void *)(uintptr_t)((i + bit) << 12);
        }
    }
    return NULL;
}

void freePage(void *pageAddress) {
    uintptr_t pageId = (uintptr_t)pageAddress >> 12;
    allocatedPages[pageId / 32] &= ~(1 << (pageId % 32));
    kernelPages[pageId].present = 0;
}

void markMMIO(void *address) {
    uintptr_t pageId = (uintptr_t)address >> 12;
    allocatedPages[pageId / 32] |= 1 << (pageId % 32);
    kernelPages[pageId].present = 1;
    kernelPages[pageId].writable = 1;
    kernelPages[pageId].isVolatile = 1;
    kernelPages[pageId].pageId = pageId;
}