#include "log.h" #include "kernel.h" #include "mem.h" #include #include "multiboot.h" #define PMMNGR_BLOCKS_PER_BYTE 8 #define PMMNGR_BLOCK_SIZE 4096 #define PMMNGR_MAX_BLOCKS 1048576 // 4096*1048576 = 2^32 bytes (maxium addressable memory ~4GB) #define PMMNGR_MAP_SIZE PMMNGR_MAX_BLOCKS/PMMNGR_BLOCKS_PER_BYTE/4 // defined in linker.ld and asm_start.s extern uint32_t kernel_start[]; extern uint32_t kernel_end[]; extern uint32_t stack_top[]; extern uint32_t stack_bottom[]; // sysfs inpue uint32_t sysfs_in=128; //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]; //128KiB //track number of free blocks static uint32_t mem_free_blocks; //number of free blocks static char *memmap_type_to_string[]= { "Usable", "Reserved", "ACPI reclaimable", "ACPI NVS", "Bad Memory" }; // bit funcs! static void mmap_set(int bit) { _mmngr_memory_map[bit / 32] |= (1 << (bit % 32)); } static void mmap_unset(int bit) { _mmngr_memory_map[bit / 32] &= ~ (1 << (bit % 32)); } static int mmap_test(int bit) { return _mmngr_memory_map[bit / 32] & (1 << (bit % 32)); } // // By default, Set all of memory is in use static void pmmngr_init () { mem_free_blocks=0; for(int i=0;i0; blocks--) { // if(mmap_test(align))kpanic("already initialized"); mmap_unset (align++); mem_free_blocks++; } } static void pmmngr_deinit_region (uint32_t base, uint32_t size) { uint32_t align = base / PMMNGR_BLOCK_SIZE; uint32_t end_align = (base+size-1) / PMMNGR_BLOCK_SIZE; uint32_t blocks = end_align-align+1; if(size%PMMNGR_BLOCK_SIZE)blocks++; for (; blocks>0; blocks--) { // if(mmap_test(align))kpanic("already de-initialized"); mmap_set (align++); mem_free_blocks--; } } void* mem_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 mem_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); } uint32_t mem_get_free_blocks_count() { return mem_free_blocks; } /** initialize physical memory manager */ uint32_t mem_init(multiboot_information *info) { klog("markers in kernel binary:"); klog("kernel loaded at: 0x%08X- 0x%08X",kernel_start,kernel_end); klog("initial stack at: 0x%08X- 0x%08X",stack_top,stack_bottom); fixme("check if kernel/ramimage size/pos does not exceed first 32mb (better vmem dynamically) limits!"); fixme("communicate pages to vmmem to identity map in kernel!"); 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 (); //mark all memory as used uint64_t memmap=info->mmap_addr; uint64_t length=info->mmap_length; uint32_t total_mem=0; // 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; klog("%08X - %08X (%d bytes)/ type: %s, (size: %d)", (uint32_t)mem_start, (uint32_t)mem_end, (uint32_t)(mem_end-mem_start), memmap_type_to_string[mmap->type-1], mmap->size); uint32_t mem=mmap->length; //reclaimable OR usable if(mmap->type==1||mmap->type==3) { total_mem+=mem; pmmngr_init_region(mmap->base_addr,mmap->length); } //next mmap_addr+=mmap->size+4; } // deinit first page (coz address=0 reserved for failure) pmmngr_deinit_region(0,4096); // 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); pmmngr_deinit_region(mod->mod_start,((uint32_t)mod->mod_end-(uint32_t)mod->mod_start)); mod++; } } // deinitialize kernel simply with this: pmmngr_deinit_region(kernel_start,((uint32_t)kernel_end-(uint32_t)kernel_start)); // or better via ELF symbols: (TODO!) if(info->flags&&1<<5) { fixme("parse ELF sections of our kernel."); } else kpanic("Can not find ELF symbols."); klog("Free 4K blocks: %d",mem_free_blocks); klog("Usable ~%d / %d MB ",mem_free_blocks*4096/1024/1024,total_mem/1024/1024); return 0; } void mem_sysfs(ringbuffer *r, void (*f)(ringbuffer *r,char *fmt, ...)) { f(r,"physical memory manager"); f(r,"free 4096kb blocks : %d",mem_free_blocks); f(r,"free bytes : %d",mem_free_blocks*4096); f(r,"in value : 0x%08X",sysfs_in); } void mem_sysfs_set(uint32_t set) { sysfs_in=set; }