#include #include "kernel.h" #include "multiboot.h" #define PMMNGR_BLOCKS_PER_BYTE 8 #define PMMNGR_BLOCK_SIZE 4096 #define PMMNGR_MAX_BLOCKS 1048576 #define PMMNGR_MAP_SIZE PMMNGR_MAX_BLOCKS/PMMNGR_BLOCKS_PER_BYTE/4 // defined in linker.ld and multiboot.s extern uint32_t kernel_start[]; extern uint32_t kernel_end[]; extern uint32_t stack_top[]; extern uint32_t stack_bottom[]; //memory map bit array. Each bit represents a 4KB memory block, //so uint32_t represents 8*4 blocks static uint32_t _mmngr_memory_map[PMMNGR_MAP_SIZE]; static uint32_t mem_free_blocks; //number of free blocks static uint32_t mem_max_block; //index of highest usable block static uint32_t mem_min_block; //index of lowset block available for alloc char *memmap_type_to_string[]= { "Usable", "Reserved", "ACPI reclaimable", "ACPI NVS", "Bad Memory" }; uint32_t mem_get_free_blocks_count() { return mem_free_blocks; } // bit funcs! void mmap_set(int bit) { _mmngr_memory_map[bit / 32] |= (1 << (bit % 32)); } void mmap_unset(int bit) { _mmngr_memory_map[bit / 32] &= ~ (1 << (bit % 32)); } int mmap_test(int bit) { return _mmngr_memory_map[bit / 32] & (1 << (bit % 32)); } // // By default, Set all of memory is in use void pmmngr_init () { mem_free_blocks=0; for(int i=0;i0; blocks--) { mmap_unset (align++); mem_free_blocks++; } } void pmmngr_deinit_region (uint32_t base, uint32_t size) { uint32_t align = base / PMMNGR_BLOCK_SIZE; uint32_t blocks = size / PMMNGR_BLOCK_SIZE; if(size%PMMNGR_BLOCK_SIZE)blocks++; for (; blocks>0; blocks--) { mmap_set (align++); mem_free_blocks--; } } void* pmmngr_alloc_block () { int frame = mmap_first_free (); if (frame == -1) { kpanic("OUT OF MEMORY (alloc_block)"); return 0; //out of memory } mmap_set (frame); mem_free_blocks--; uint32_t addr = frame * PMMNGR_BLOCK_SIZE; //klog("alloc block (%d) 0x%08X)",frame,addr); return (void*)addr; } void pmmngr_free_block (void* p) { uint32_t addr = (uint32_t)(uint32_t*)p; int frame = addr / PMMNGR_BLOCK_SIZE; if(mmap_test(frame)) { mmap_unset (frame); mem_free_blocks++; } else { //klog("free block (%d) 0x%08X)",frame,addr); kpanic("trying to free, free physical mem!"); } //klog("free block (%d) 0x%08X)",frame,addr); } // returns index of first block outside of kerel-land uint32_t mem_init(multiboot_information *info) { if(info->flags&&1<<6) { klog("memory map of length %d provided by bootloader",info->mmap_length); } else kpanic("Unable to continue without memory map, sorry!"); pmmngr_init (); //clear memmap uint64_t memmap=info->mmap_addr; uint64_t length=info->mmap_length; klog("kernel loaded at: 0x%08X- 0x%08X",kernel_start,kernel_end); klog("initial stack at: 0x%08X- 0x%08X",stack_top,stack_bottom); // count available mem and track high_end of usable memory uint32_t total_mem=0, highest_end; // iterate : print memory map, calc blocks, deinit for(uint32_t mmap_addr=memmap;mmap_addrbase_addr; uint64_t mem_end=mmap->base_addr+mmap->length; #ifdef MEM_PRINT_MEMORYMAP klog("%08X - %08X / type: %s, (size: %d)", (uint32_t)mem_start, (uint32_t)mem_end, memmap_type_to_string[mmap->type-1], mmap->size); #endif uint32_t mem=mmap->length; //reclaimable OR usable if(mmap->type==1||mmap->type==3) { total_mem+=mem; highest_end=mmap->base_addr+mmap->length-1; pmmngr_init_region(mmap->base_addr,mmap->length); } //next mmap_addr+=mmap->size+4; } uint32_t blocks=highest_end/4096+1; mem_max_block=blocks/32+1; // deinit modules memory if(info->flags&&1<<3) { multiboot_mod *mod=(multiboot_mod *)info->mods_addr; for(int i=0;imods_count;i++) { klog("mod 0x%08X-0x%08X : %s", mod->mod_start,mod->mod_end, mod->string); mem_min_block=mod->mod_end/PMMNGR_BLOCK_SIZE+1; //pmmngr_deinit_region(mod->mod_start,((uint32_t)mod->mod_end-(uint32_t)mod->mod_start)+1); mod++; } } // deinitialize kernel //pmmngr_deinit_region(kernel_start,((uint32_t)kernel_end-(uint32_t)kernel_start)+1); // we deinit everything below mem_min_block anyway pmmngr_deinit_region(0,mem_min_block*PMMNGR_BLOCK_SIZE); klog("Usable ~%d / %d MB ",mem_free_blocks*4096/1024/1024,total_mem/1024/1024); klog( "Free 4K blocks: %d (first free: %d)",mem_free_blocks,mem_min_block); return mem_min_block; }