#include #include /* * Der Einfachheit halber deklarieren wir die maximal benoetige Bitmapgroesse * statisch (Wir brauchen 4 GB / 4 kB = 1M Bits; 1M Bits sind 1M/32 = 32k * Eintraege fuer das Array) * * Willkuerliche Festlegung: 1 = Speicher frei, 0 = Speicher belegt */ #define BITMAP_SIZE 32768 static uint32_t bitmap[BITMAP_SIZE]; void pmm_mark_used(void* page); void pmm_init(struct multiboot_info* mb_info) { //kprintf("[ PMM ] Bitmap located at 0x%x\n", bitmap); struct multiboot_mmap* mmap = mb_info->mbs_mmap_addr; struct multiboot_mmap* mmap_end = (void*) ((uintptr_t) mb_info->mbs_mmap_addr + mb_info->mbs_mmap_length); /* Per Default ist erst einmal alles reserviert */ memset(bitmap, 0, sizeof(bitmap)); /* * Nur, was die BIOS-Memory-Map als frei bezeichnet, wird wieder als frei * markiert */ while (mmap < mmap_end) { if (mmap->type == 1) { /* Der Speicherbereich ist frei, entsprechend markieren */ uintptr_t addr = mmap->base; uintptr_t end_addr = addr + mmap->length; while (addr < end_addr) { pmm_free((void*) addr); addr += 0x1000; } } mmap++; } /* Den Kernel wieder als belegt kennzeichnen */ uintptr_t addr = (uintptr_t)0; while (addr < (uintptr_t) 0x300000) { pmm_mark_used((void*) addr); addr += 0x1000; } /* * Die Multibootstruktur auch, genauso wie die Liste von Multibootmodulen. * Wir gehen bei beiden davon aus, dass sie maximal 4k gross werden */ struct multiboot_module* modules = mb_info->mbs_mods_addr; pmm_mark_used(mb_info); pmm_mark_used(modules); /* Und die Multibootmodule selber sind auch belegt */ int i; for (i = 0; i < mb_info->mbs_mods_count; i++) { addr = modules[i].mod_start; while (addr < modules[i].mod_end) { pmm_mark_used((void*) addr); addr += 0x1000; } } } void* pmm_alloc(void) { int i, j; /* * Zunaechst suchen wir komplette Eintraege ab. Wenn der Eintrag nicht null * ist, ist mindestens ein Bit gesetzt, d.h. hier ist ein Stueck Speicher * frei */ for (i = 0; i < BITMAP_SIZE; i++) { if (bitmap[i] != 0) { /* Jetzt muessen wir nur noch das gesetzte Bit finden */ for (j = 0; j < 32; j++) { if (bitmap[i] & (1 << j)) { bitmap[i] &= ~(1 << j); return (void*)( (i * 32 + j) * 4096); } } } } /* Scheint wohl nichts frei zu sein... */ return NULL; } void pmm_mark_used(void* page) { uintptr_t index = (uintptr_t) page / 4096; bitmap[index / 32] &= ~(1 << (index % 32)); //kprintf("[ PMM ] Reserved 4096 Bytes at address 0x%x\n", page); } void pmm_free(void* page) { uintptr_t index = (uintptr_t) page / 4096; bitmap[index / 32] |= (1 << (index % 32)); } /* gibt die angegebene Größe als zusammenhängenden * Speicherbereich zurück und markiert ihn in der * Bitmap als reserviert * * Größe des Speicherbereiches in Bytes * noch nicht ideal, gibt immer 128 KB Blöcke zurück */ void *kalloc(size_t size) { uint32_t pageCount = size / 4096; if(size % 4096 != 0) pageCount++; if(pageCount == 0) return NULL; if(pageCount < 1) pageCount = 1; //kprintf("[ PMM ] Allocating %d Pages (%d Bytes)\n", pageCount, size); if(pageCount <= 32) { int i = 0; for(i = 0; i < BITMAP_SIZE; i++) { if(bitmap[i] == 0xFFFFFFFF) { // 32 freie Seiten bitmap[i] = 0; // Speicher reservieren return (void*)(i * 32 * 4096); } } } else { int bmpCount = pageCount / 32; int i; bool found = false; for(i = 0; i < BITMAP_SIZE; i++) { if(bitmap[i] == 0xFFFFFFFF) { int j; for(j = 1; j <= bmpCount; j++) { if(bitmap[i + j] == 0xFFFFFFFF) { found = true; } else { found = false; break; } } if(found) { for(j = 1; j <= bmpCount; j++) { bitmap[i + j] = 0; // reservieren } //kprintf("[ PMM ] Allocated %d Bytes at 0x%x", size, i * 32 * 4096); return (void *)(i * 32 * 4096); } } } } kprintf("[ PMM ] Not enough memory!\n"); return NULL; }