Implemented a proper libk

This commit is contained in:
2024-10-09 16:45:37 +02:00
parent 9ff817b935
commit 95d32f025a
45 changed files with 1713 additions and 1524 deletions
+114
View File
@@ -0,0 +1,114 @@
#include <memory/virtual.h>
#include <memory/physical.h>
#include <memory/malloc.h>
#include <stdbool.h>
#include <stdint.h>
mallocNode_t* mallocListHead = NULL;
uint32_t mallocVirtualAddr = 0;
uint32_t mallocPhysicalAddr = 0;
uint32_t mallocPages = 0;
void mallocInit(uint32_t size) {
mallocPages = size / PAGE_SIZE;
if (size % PAGE_SIZE > 0) { mallocPages++; }
mallocPhysicalAddr = (uint32_t)allocBlocks(mallocPages);
mallocListHead = (mallocNode_t*)mallocVirtualAddr;
// Map pages
for (uint32_t i = 0, virtualAddr = mallocVirtualAddr; i < mallocPages; i++, virtualAddr += PAGE_SIZE) {
mapPage((void*)(mallocPhysicalAddr + i * PAGE_SIZE), (void*)virtualAddr);
ptEntry_t* page = getPage(virtualAddr);
SET_ATTR(page, PTE_READ_WRITE);
}
if (mallocListHead) {
mallocListHead->size = (mallocPages * PAGE_SIZE) - sizeof(mallocNode_t);
mallocListHead->free = true;
mallocListHead->next = NULL;
}
}
void mallocSplit(mallocNode_t* node, uint32_t size) {
if (node->size < size + sizeof(mallocNode_t)) { return; } // Can't split - node too small
// Remainder node
mallocNode_t* newNode = (mallocNode_t*)((void*)node + size + sizeof(mallocNode_t));
newNode->size = node->size - size - sizeof(mallocNode_t);
newNode->free = true;
newNode->next = node->next;
// Split node
node->size = size;
node->free = false;
node->next = newNode;
}
void* mallocNextNode(uint32_t size) {
if (size == 0) { return NULL; } // Why would you try that? (undefined behaviour i guess)
mallocNode_t* current = mallocListHead;
if (mallocListHead->size == 0) { mallocInit(size); }
while (((current->size < size) || !current->free) && current->next != NULL) {
current = current->next;
}
if (current->size == size) {
current->free = false;
} else if (current->size > size + sizeof(mallocNode_t)) {
mallocSplit(current, size); // Modifies current into the right size and makes it point to the remainder
} else { // There's no large enough node -> try to allocate more pages
uint8_t pageCount = 1;
while (current->size + pageCount * PAGE_SIZE < size + sizeof(mallocNode_t)) {
pageCount++;
}
// Allocate and map new pages
uint32_t virtualAddr = mallocVirtualAddr + mallocPages * PAGE_SIZE;
for (uint32_t i = 0; i < pageCount; i++) {
ptEntry_t page = 0;
uint32_t* temp = allocPage(&page);
mapPage((void*)temp, (void*)virtualAddr);
SET_ATTR(&page, PTE_READ_WRITE);
virtualAddr += PAGE_SIZE;
current->size += PAGE_SIZE;
mallocPages++;
}
mallocSplit(current, size);
}
return (void*)current + sizeof(mallocNode_t);
}
void mallocMergeFree() {
mallocNode_t* current = mallocListHead;
while (current && current->next != NULL) {
if (current->free && current->next->free) {
current->size += (current->next->size) + sizeof(mallocNode_t);
current->next = current->next->next;
}
current = current->next;
}
}
void mallocFree(void* ptr) {
mallocNode_t* current = mallocListHead;
while (current->next) {
if ((void*)current + sizeof(mallocNode_t) == ptr) {
current->free = true;
mallocMergeFree();
break;
}
current = current->next;
}
}
+122
View File
@@ -0,0 +1,122 @@
#include <memory/physical.h>
#include <memory/addresses.h>
#include <string.h>
#include <stdint.h>
uint32_t* memoryMap = 0;
uint32_t maxBlocks;
uint32_t usedBlocks = 0;
void setBlock(uint32_t block) {
// Set the right bit to 1
memoryMap[block/32] |= (1 << (block % 32));
}
void unsetBlock(uint32_t block) {
// Set the right bit to 0
memoryMap[block/32] &= ~(1 << (block % 32));
}
uint8_t testBlock(uint32_t block) {
// Check the bit
return memoryMap[block/32] & (1 << (block % 32)) ? 1 : 0;
}
// TODO: Refactor whatever the fuck this is
int32_t findFreeBlocks(uint32_t blockCount) {
if (blockCount == 0) { // Error
return -1;
}
uint32_t maxBlockEntries = maxBlocks / 32;
for (uint32_t i = 0; i < maxBlockEntries; i++) {
if (memoryMap[i] != 0xffffffff) {
for (uint8_t j = 0; j < 32; j++) {
uint32_t block = 1 << j;
if (!(memoryMap[i] & block)) {
// uint32_t startBlock = i * 32 + block;
// uint32_t freeBlocks = 0;
for (uint32_t count = i, freeBlocks = 0; count < blockCount; count++) {
if (j + count > 31 && i + 1 <= maxBlocks / 32) {
if (!(memoryMap[i+1] & (1 << (j + count)))) {
freeBlocks++;
}
} else {
if (!(memoryMap[i] & (1 << (j + count)))) {
freeBlocks++;
}
}
if (freeBlocks == blockCount) {
return i * 32 + j;
}
}
}
}
}
}
return -1; // No free memory found :/
}
void setupPhysicalMemoryManager(uint32_t startAddress, uint32_t size) {
memoryMap = (uint32_t*)startAddress;
maxBlocks = size / BLOCK_SIZE;
usedBlocks = maxBlocks;
memset((char*)memoryMap, 0xff, maxBlocks / BLOCKS_PER_BYTE);
}
void initMemoryRegion(uint32_t baseAddress, uint32_t size) {
uint32_t align = baseAddress / BLOCK_SIZE;
uint32_t blockCount = size / BLOCK_SIZE;
while (blockCount-- > 0) {
unsetBlock(align++);
usedBlocks--;
}
setBlock(0); // Make sure we don't override the first block that contains IDT, BIOS stuff etc.
}
void deinitMemoryRegion(uint32_t baseAddress, uint32_t size) {
uint32_t align = baseAddress / BLOCK_SIZE;
uint32_t blockCount = size / BLOCK_SIZE;
while (blockCount-- > 0) {
setBlock(align++);
usedBlocks++;
}
}
void* allocBlocks(uint32_t blockCount) {
if ((maxBlocks - usedBlocks) < blockCount) {
return NULL;
}
int32_t startBlock = findFreeBlocks(blockCount);
if (startBlock == -1) {
return NULL;
}
for (uint32_t i = 0; i < blockCount; i++) {
setBlock(startBlock + i);
usedBlocks++;
}
return (void*)(startBlock * BLOCK_SIZE);
}
void freeBlocks(void* address, uint32_t blockCount) {
uint32_t startBlock = (uint32_t)(address) / BLOCK_SIZE;
for (uint32_t i = 0; i < blockCount; i++) {
unsetBlock(startBlock + i);
usedBlocks--;
}
setBlock(0); // Make sure that block 0 is always set
}
+153
View File
@@ -0,0 +1,153 @@
#include <memory/virtual.h>
#include <memory/physical.h>
#include <memory/addresses.h>
#include <string.h>
#include <stdint.h>
pageDirectory_t* currentPd = NULL;
ptEntry_t* getPtEntry(pageTable_t* pt, uint32_t virtualAddress) {
if (pt) return &pt->entries[PT_INDEX(virtualAddress)];
return NULL;
}
pdEntry_t* getPdEntry(pageDirectory_t* pd, uint32_t virtualAddress) {
if (pd) return &pd->entries[PT_INDEX(virtualAddress)]; // It it supposed to be PT_INDEX, don't worry
return NULL;
}
ptEntry_t* getPage(uint32_t virtualAddress) {
pageDirectory_t* pd = currentPd;
pdEntry_t* entry = &pd->entries[PD_INDEX(virtualAddress)];
pageTable_t* table = (pageTable_t*)PAGE_PHYS_ADDRESS(entry);
ptEntry_t* page = &table->entries[PT_INDEX(virtualAddress)];
return page;
}
void* allocPage(ptEntry_t* page) {
void* block = allocBlocks(1);
if (block) {
SET_FRAME(page, (uint32_t)block);
SET_ATTR(page, PTE_PRESENT);
}
return block;
}
void freePage(ptEntry_t* page) {
void* address = (void*)PAGE_PHYS_ADDRESS(page);
if (address) {
freeBlocks(address, 1);
}
CLEAR_ATTR(page, PTE_PRESENT);
}
uint8_t setPageDirectory(pageDirectory_t* pd) {
if (!pd) { return 1; } // Nuh uh
currentPd = pd;
// cr3 (Control register 3) - current page dir address
__asm__ volatile("movl %%eax, %%cr3" : : "a"(currentPd));
return 0; // Success
}
void flushTlbEntry(uint32_t virtualAddress) {
__asm__ volatile("cli; invlpg (%0); sti" : : "r"(virtualAddress));
}
uint8_t mapPage(void* physicalAddr, void* virtualAddr) {
pageDirectory_t* pd = currentPd;
pdEntry_t* entry = &pd->entries[PD_INDEX((uint32_t)virtualAddr)];
if (!TEST_ATTR(entry, PTE_PRESENT)) {
// Assuming that the page is not allocated since it's not present
pageTable_t* table = (pageTable_t*)allocBlocks(1);
if (!table) return 1; // Out of memory!!
// Clear page table (may be slow?)
memset(table, 0, sizeof(pageTable_t));
pdEntry_t* entry = &pd->entries[PD_INDEX((uint32_t)virtualAddr)];
// Enable attributes and map in table
SET_ATTR(entry, PDE_PRESENT);
SET_ATTR(entry, PDE_READ_WRITE);
SET_FRAME(entry, (uint32_t)table);
}
pageTable_t* table = (pageTable_t*)PAGE_PHYS_ADDRESS(entry);
ptEntry_t* page = &table->entries[PT_INDEX((uint32_t)virtualAddr)];
SET_ATTR(page, PTE_PRESENT);
SET_FRAME(page, (uint32_t)physicalAddr);
return 0; // Success
}
void unmapPage(void* virtualAddress) {
ptEntry_t* page = getPage((uint32_t)virtualAddress);
SET_FRAME(page, 0);
CLEAR_ATTR(page, PDE_PRESENT);
}
uint8_t setupVirtualMemoryManager() {
// Create a default page dir
pageDirectory_t* dir = (pageDirectory_t*)allocBlocks(3);
if (!dir) { return 1; } // Out of memory
memset(dir, 0, sizeof(pageDirectory_t));
for (uint32_t i = 0; i < 1024; i++) {
dir->entries[i] = 0x02; // Supervisor, r/w, not present
}
// Alloc default page table
pageTable_t* table = (pageTable_t*)allocBlocks(1);
if (!table) { return 1; } // Out of memory
// Alloc a 3GB page
pageTable_t* table3gb = (pageTable_t*)allocBlocks(1);
if (!table) { return 1; } // Out of memory
memset(table, 0, sizeof(pageTable_t));
memset(table3gb, 0, sizeof(pageTable_t));
// Identity map first 4MB
for (uint32_t i = 0, frame = 0, virt = 0; i < 1024; i++, frame += PAGE_SIZE, virt += PAGE_SIZE) {
ptEntry_t page = 0;
SET_ATTR(&page, PTE_PRESENT);
SET_ATTR(&page, PTE_READ_WRITE);
SET_FRAME(&page, frame);
table3gb->entries[PT_INDEX(virt)] = page;
}
// Map kernel to 3GB+
for (uint32_t i = 0, frame = KERNEL_LOC, virt = 0xc0000000; i < 1024; i++, frame += PAGE_SIZE, virt += PAGE_SIZE) {
ptEntry_t page = 0;
SET_ATTR(&page, PTE_PRESENT);
SET_ATTR(&page, PTE_READ_WRITE);
SET_FRAME(&page, frame);
table->entries[PT_INDEX(virt)] = page;
}
pdEntry_t* entry = &dir->entries[PD_INDEX(0xc0000000)];
SET_ATTR(entry, PDE_PRESENT);
SET_ATTR(entry, PDE_READ_WRITE);
SET_FRAME(entry, (uint32_t)table);
pdEntry_t* entry2 = &dir->entries[PD_INDEX(0x00000000)];
SET_ATTR(entry2, PDE_PRESENT);
SET_ATTR(entry2, PDE_READ_WRITE);
SET_FRAME(entry2, (uint32_t)table3gb);
setPageDirectory(dir);
// ENABLE PAGING!!! Set PG bit 31 and PE bit 0 in cr0
__asm__ volatile("movl %cr0, %eax; orl $0x80000001, %eax; movl %eax, %cr0");
return 0; // Success
}