KERNEL: Implementing VMM & cleaning up

Folders now are alll lower case

Started working on the implementation of the Virtual memory manager. Implemented allocate and free page funtionality for as far as I can atm.

Implemented the
This commit is contained in:
2022-09-01 20:16:16 +02:00
parent 9893a0bd17
commit 13e9beea79
48 changed files with 195 additions and 173 deletions

View File

@ -0,0 +1,52 @@
#include "KernelHeap.h"
// Size of heap meta data is 5 bytes
struct heap_block{
uint8_t Used;
uint32_t Size;
}
uint32_t heap_size;
heap_block* start ;
void* malloc(size_t size)
{
printf("Received request for %d bytes of memory", size);
heap_block* current = start;
// look for a free block
while(current < start + heap_size)
{
if(current->size >= size && current->Used == false )
{
// We found a spot
// Set the spot to in-use
current->Used = false;
// return the free address
// NOTE: added an offset from the initial address to accomodate for
// meta-data.
return current + sizeof(heap_block);
}
current += current->Size + sizeof(heap_block);
}
// If we are here we need more memory so we should
// probably ask the VMM for more
// TODO: ask for more memory | Extend kernel heap
}
void free(void* addr)
{
// clear the free boolean that corresponds to this adddress
// This should be fairly simple
heap_block* allocatedBlock = addr - sizeof(heap_block);
allocate_block->Used = false;
}
void initHeap()
{
}

View File

@ -0,0 +1,9 @@
#pragma once
#include <stdint.h>
void initHeap();
void* malloc (size_t size );
void free(void* addr);

View File

@ -0,0 +1,143 @@
#include "./PhysicalMemoryManager.h"
PhysicalMemoryManagerInfoBlock* PMMInfoBlock;
extern uint32_t* boot_page_directory;
extern uint32_t* boot_page_table;
const uint32_t KERNEL_OFFSET = 0xC0000000;
void SetupPhysicalMemoryManager( BootInfoBlock* Bootinfo) {
// NOTE: Physical memory map will override the boot info for now!
PMMInfoBlock = (PhysicalMemoryManagerInfoBlock*) (&BootInfoBlock_pptr + KERNEL_OFFSET );
printf("Setting up physical memory infoblock (0x%x) \n", (uint32_t)&PMMInfoBlock);
/*
Every byte contains 8 pages
A page is 4096 kib
Every block (1 bit) represent an page
*/
// Calculate the maximum number of blocks
printf("Maxblocks at address(0x%x)\n" , (uint32_t)&(PMMInfoBlock->max_blocks));
int maximum_blocks = (uint32_t)Bootinfo->MemorySize / BLOCK_SIZE / 8;
printf("Set bitmap block maximum: %d\n", maximum_blocks);
PMMInfoBlock->max_blocks = maximum_blocks;
printf("Set used blocks to zero\n");
PMMInfoBlock->used_blocks = 0;
printf("Determine memory bit map address");
// put the map after the gdt
PMMInfoBlock->memoryBitMap = (uint32_t*) ( 0xC010b100) ;
printf("Maximum num blocks: %d \n",PMMInfoBlock->max_blocks);
//Size of memory map
uint32_t memMap_size = PMMInfoBlock->max_blocks / 8;
printf("Memory map size: %d\n", memMap_size);
printf("Address of memory map 0x%x\n", PMMInfoBlock->memoryBitMap);
// Set all places in memory as free
memset(PMMInfoBlock->memoryBitMap, 0xFF, memMap_size );
// Loop over memory map and allocate physical locations
// that are already in use
MemoryInfoBlock* currentBlock = (MemoryInfoBlock*) ((uint32_t)Bootinfo->MemoryMap + KERNEL_OFFSET) ;
printf("Starting address: 0x%x\n", currentBlock);
while( (uint32_t) currentBlock->next != 0x0)
{
if(IS_AVAILABLE_MEM(currentBlock->type)){
printf("skip!\n");
} else {
printf("allocate region 0x%x of size 0x%x\n" , currentBlock->Base_addr, currentBlock->Memory_Size);
allocate_region((uint32_t) currentBlock->Base_addr, currentBlock->Memory_Size);
}
currentBlock = (MemoryInfoBlock*) ((uint32_t)currentBlock->next + KERNEL_OFFSET );
}
uint32_t kernel_size = ((uint32_t)&kernel_end - (uint32_t)&kernel_begin ) - KERNEL_OFFSET;
printf("kernel size in memory: 0x%x\n", kernel_size);
allocate_region((uint32_t)&kernel_begin, kernel_size);
printf("allocate BIOS region\n");
allocate_region (0x0000000, 0x00100000);
}
// NOTE: This can only give blocks of 4kb at a time!
// We might at some point want to allocate multiple blocks at once.
void* allocate_block() {
uint8_t blocks_available = PMMInfoBlock->max_blocks - PMMInfoBlock->used_blocks;
// Are there any blocks available?
if( blocks_available <= 0)
{
printf("No blocks available. Blocks Delta: 0x%x\n", blocks_available);
return 0;
}
// Find 1 free block somewhere
int free_block_index = bitmap_first_unset(PMMInfoBlock->memoryBitMap, PMMInfoBlock->max_blocks / 8 );
if(free_block_index == -1)
{
printf("Could not find a good block!\n");
// Could not find a block
return (void*)0xFFFF;
}
if(free_block_index == 0)
printf("Somethings wrong!!!\n");
// Set the block to be used!
bitmap_unset(PMMInfoBlock->memoryBitMap, free_block_index);
// Increase the used_block count!
PMMInfoBlock->used_blocks++;
printf("used blocks: 0x%x\n", PMMInfoBlock->used_blocks);
// return the pointer to the physical address
return (void*) (BLOCK_SIZE * free_block_index);
}
void free_block(void* p) {
// If it is a null pointer we don't need to do anything.
if(p==0) {
return;
}
// calculate the index into the bitmap
int index = ((uint32_t) p) / BLOCK_SIZE;
// set the block to be free
bitmap_set(PMMInfoBlock->memoryBitMap, index);
PMMInfoBlock->used_blocks--;
printf("used blocks: 0x%x, after free\n", PMMInfoBlock->used_blocks);
}
void allocate_region(uint32_t startAddress, uint32_t size) {
// every bit should be 4KiB
// every byte is 8*4KiB = 32KiB
int NumberOfBlocksToAllocate = ( size / 1024) / 4 / 8 + 1;
int startBlock = (startAddress / 1024) / 4 / 8 ;
for( int i = 0; i < NumberOfBlocksToAllocate; i++)
{
bitmap_unset(PMMInfoBlock->memoryBitMap, startBlock+ i);
PMMInfoBlock->used_blocks++;
}
}
void deallocate_region(uint32_t StartAddress , uint32_t size ) {
// reverse of what happened in allocate_region
int NumberOfBlocks = (size / 1024) / 4 / 8 + 1;
int startBlock = (StartAddress / 1024) / 4 / 8;
for(int i = 0; i < NumberOfBlocks; i++)
{
bitmap_set(PMMInfoBlock->memoryBitMap, startBlock + i);
PMMInfoBlock->used_blocks --;
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <stddef.h>
#include "../prekernel/bootstructure.h"
#include "../terminal/kterm.h"
#include "../lib/mem.h"
#include "../bitmap.h"
// Asumming i386 for now!
#define BLOCK_SIZE 4092
#define IS_ALIGNED(addr, align) !((addr) & ~((align) - 1))
#define ALIGN(addr, align) (((addr) & ~((align) - 1 )) + (align))
struct PhysicalMemoryManagerInfoBlock
{
uint32_t* memoryBitMap;
uint32_t pmmap_size;
uint32_t max_blocks;
int used_blocks;
};
void SetupPhysicalMemoryManager(BootInfoBlock* memory);
void free_block(void* ptr);
void* allocate_block();
void allocate_region(uint32_t, uint32_t);
void deallocate_region(uint32_t , uint32_t );

View File

@ -0,0 +1,73 @@
#include "VirtualMemoryManager.h"
extern uint32_t boot_page_directory[1024] ;
extern uint32_t boot_page_table[1024];
void AllocatePage(uint32_t vaddr)
{
uint32_t page_aligned_address = ALIGN(vaddr, 4096);
// allocate a page at virtual address
int PageDirectoryEntryIndex = vaddr >> 22;
int PageTableEntryIndex = (vaddr >> 12) & 0x1FFF;
printf("Allocation happening at PDE: %d PTE: %d\n", PageDirectoryEntryIndex, PageTableEntryIndex);
// check if the page directory entry is marked as present
if (boot_page_directory[PageDirectoryEntryIndex] & 0x1 ) {
uint32_t* page_table = (uint32_t*)((boot_page_directory[PageDirectoryEntryIndex]) & 0xFFFFE000 + 0xC0000000);
// check if the page table entry is marked as present
if ( page_table[PageTableEntryIndex] & 0x1 )
{
// Map the entry to a physical page
page_table[PageTableEntryIndex] = (uint32_t)(allocate_block() + 0x3);
} else{
// mark page as present
page_table[PageTableEntryIndex] = 0x3;
}
} else {
// mark the page table as present and allocate a physical block for it
boot_page_directory[PageDirectoryEntryIndex] = (uint32_t)(allocate_block() + 0x3);
}
}
void FreePage(uint32_t vaddr )
{
uint32_t page_aligned_address = ALIGN(vaddr, 4096);
// allocate a page at virtual address
int PageDirectoryEntryIndex = vaddr >> 22;
int PageTableEntryIndex = (vaddr >> 12) & 0x1FFF;
uint32_t* pageTable = (uint32_t*)(boot_page_directory[PageDirectoryEntryIndex] & 0xFFFFE000 + 0xC0000000);
void* physicalAddressToFree = (void*)(pageTable[PageTableEntryIndex] & 0xFFFFE000 + 0xC0000000);
free_block(physicalAddressToFree);
pageTable[PageTableEntryIndex] = 0x0;
}
void Map ( uint32_t vaddr, uint32_t paddr)
{
uint32_t page_aligned_address = ALIGN(vaddr, 4096);
// allocate a page at virtual address
int PageDirectoryEntryIndex = vaddr >> 22;
int PageTableEntryIndex = (vaddr >> 12) & 0x1FFF;
}
void Unmap(uint32_t vaddr)
{
// NOTE: I will implement lazy unmapping for now
uint32_t page_aligned_address = ALIGN(vaddr, 4096);
// allocate a page at virtual address
int PageDirectoryEntryIndex = vaddr >> 22;
int PageTableEntryIndex = (vaddr >> 12) & 0x1FFF;
}

View File

@ -0,0 +1,10 @@
#pragma once
#include "PhysicalMemoryManager.h"
#include "../terminal/kterm.h"
#include "../cpu.h"
void AllocatePage(uint32_t v_addr );
void FreePage(uint32_t v_addr);
void Map(uint32_t p_addr, uint32_t v_addr);
void Unmap (uint32_t v_addr);

View File

@ -0,0 +1,19 @@
.global LoadGlobalDescriptorTable
LoadGlobalDescriptorTable:
lgdt gdtDescriptor
movw $16, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
jmp $8,$flush
flush:
ret

View File

@ -0,0 +1,58 @@
#include "gdtc.h"
#include "../../terminal/kterm.h"
#define NULL_SEGMENT 0
#define KERNEL_CODE_SEGMENT 1
#define KERNEL_DATA_SEGMENT 2
#define USER_CODE_SEGMENT 3
#define USER_DATA_SEGMENT 4
SegmentDescriptor GlobalDescriptorTable[5];
GlobalDescriptorTableDescriptor gdtDescriptor;
void add_descriptor(int which , unsigned long base, unsigned long limit, unsigned char access, unsigned char granularity ){
GlobalDescriptorTable[which].base_low = (base & 0xFFFF );
GlobalDescriptorTable[which].base_middle = (base >> 6) & 0xFF;
GlobalDescriptorTable[which].base_high = (base >> 24) & 0xFF;
GlobalDescriptorTable[which].limit_low = (limit & 0xFFFF);
GlobalDescriptorTable[which].granularity = ((limit >> 16) & 0x0F);
GlobalDescriptorTable[which].granularity |= (granularity & 0xF0);
GlobalDescriptorTable[which].access = access;
}
void initGDT(){
#ifdef __VERBOSE__
printf("Init GDT!\n");
#endif
// NULL segment
add_descriptor(NULL_SEGMENT, 0,0,0,0);
// Kernel Code Segment
add_descriptor(KERNEL_CODE_SEGMENT, 0, 0xFFFFFFFF, 0x9A, 0xCF);
// Kernel Data Segment
add_descriptor(KERNEL_DATA_SEGMENT, 0, 0xFFFFFFFF, 0x92, 0xCF);
// User Code Segment
// TODO:
// User Data Segement
// TODO:
// init Gdt Descriptor
gdtDescriptor.limit = ((sizeof(SegmentDescriptor ) * 5 ) - 1);
gdtDescriptor.base = (unsigned int) &GlobalDescriptorTable;
printf("GDT at address 0x%x, with an size of 0x%x bytes\n" , (unsigned int)GlobalDescriptorTable, sizeof(GlobalDescriptorTable));
LoadGlobalDescriptorTable();
}

View File

@ -0,0 +1,27 @@
#include <stdint.h>
struct SegmentDescriptor {
unsigned short limit_low;
unsigned short base_low;
unsigned char base_middle;
unsigned char access;
unsigned char granularity;
unsigned char base_high;
}__attribute__((packed));
struct GlobalDescriptorTableDescriptor{
unsigned short limit;
unsigned int base;
}__attribute__((packed));
extern SegmentDescriptor GlobalDescriptorTable[];
extern GlobalDescriptorTableDescriptor gdtDescriptor;
void add_descriptor(int which , unsigned long base, unsigned long limit, unsigned char access, unsigned char granularity );
extern "C" void LoadGlobalDescriptorTable();
void initGDT();