diff --git a/kernel.c b/kernel.c index e28fe35..60632cf 100644 --- a/kernel.c +++ b/kernel.c @@ -2,7 +2,7 @@ //08/13/03 Josh Holtrop //Holtrop's Operating System //Version: 0.12 -//Modified: 11/12/03 +//Modified: 12/30/03 #include "k_defines.h" //#DEFINE's for kernel @@ -68,8 +68,8 @@ void k_init() video_drawConsole(); } - printf("HOS 0.13 - Kernel Size: %u kb\n", kernel_size()>>10); - printf("Memory available to OS: %u MB (Bytes: %u)\n", mm_megabytes, mm_totalmem); + printf("HOS 0.13 - Kernel File Size: %u kb\tData Size: %u bytes\n", kernel_size()>>10, (dword)(&_end)-(dword)(&_code)); + printf("Memory available to OS: %u MB (%u bytes)\n", mm_megabytes, mm_totalmem); printf("Free memory: %u bytes (%u pages)\n", mm_freemem(), mm_freemem()>>12); dword key = 0; diff --git a/vmm.c b/vmm.c index f748317..b4df253 100644 --- a/vmm.c +++ b/vmm.c @@ -1,10 +1,12 @@ - // vmm.c // Author: Josh Holtrop // Date: 09/30/03 // Rewritten from scratch: 12/23/03 +// Modified: 12/30/03 +// This is the initialization procedure for the Virtual Memory Manager +// It sets up the final page directory/page table setup and maps video memory, if present void vmm_init() { dword *pageTables = (dword *)0xC0104000; //this is the location of the page directory @@ -31,6 +33,7 @@ void vmm_init() } +// This function initialzes a Heap Entry Block to unused entries linked together void vmm_heb_init(HeapEntryBlock *heb) { int a; @@ -45,7 +48,7 @@ void vmm_heb_init(HeapEntryBlock *heb) } - +// This function maps a virtual address to a physical address using the page directory / page table void vmm_map1(dword virt, dword physical) { dword pde = virt >> 22; @@ -69,6 +72,7 @@ void vmm_map1(dword virt, dword physical) } +// This function maps a variable number of pages in a row void vmm_mapn(dword virt, dword physical, dword n) { for (; n > 0; n--) @@ -80,6 +84,7 @@ void vmm_mapn(dword virt, dword physical, dword n) } +// This function removes the virtual address's entry in the page directory / page table void vmm_unmap1(dword virt) { dword *pteptr = (dword *)(0xFFC00000 | ((virt & 0xFFC00000) >> 10) | ((virt & 0x003FF000) >> 10)); @@ -88,6 +93,7 @@ void vmm_unmap1(dword virt) } +// This function removes multiple pages' entries void vmm_unmapn(dword virt, dword n) { for (; n > 0; n--) @@ -98,39 +104,248 @@ void vmm_unmapn(dword virt, dword n) } +// Virtual Memory allocator function void *malloc(dword bytes) +{ + if (bytes % VMM_MALLOC_GRANULARITY) + bytes = bytes + VMM_MALLOC_GRANULARITY - (bytes % VMM_MALLOC_GRANULARITY); + void *attempt = vmm_getFreeChunk(bytes); + if (attempt) + return attempt; + if(vmm_moreCore(bytes)) + return 0; //we could not get any more heap memory + return vmm_getFreeChunk(bytes); +} + + +// This function returns a pointer if a free chunk of memory exists +void *vmm_getFreeChunk(dword bytes) { HeapEntry *he = firstHeapEntry; for (;;) { - if ((he->size >= bytes) && (he->attributes = VMM_HE_FREE)) + if (he->attributes == VMM_HE_FREE) { + if (he->size > bytes) + { + HeapEntry *nhe = vmm_nextHeapEntry(); + nhe->base = he->base; + nhe->size = bytes; + nhe->attributes = VMM_HE_USED; + he->base += bytes; + he->size -= bytes; + return (void *)(nhe->base); + } if (he->size == bytes) { he->attributes = VMM_HE_USED; return (void *)(he->base); } - else + } + he = (HeapEntry *)he->link; + if (!he) + break; + } + return 0; +} + + +// This function coalesces any two adjacent heap entries into one entry +void vmm_coalesceHeapEntry(HeapEntry *he) +{ + if (!(he->attributes == VMM_HE_FREE || he->attributes == VMM_HE_HOLE)) + return; + if (he->size == 0) + { + he->attributes = VMM_HE_UNUSED; + return; + } + HeapEntry *hec = firstHeapEntry; + for (;;) + { + if (hec->attributes == he->attributes) + { + if ((hec->base + hec->size) == he->base) //hec ends where he begins { - //get the next HeapEntry, save in it the free mem, save in this entry the used mem... + he->base = hec->base; + he->size += hec->size; + hec->attributes = VMM_HE_UNUSED; + } + if ((he->base + he->size) == hec->base) //he ends where hec begins + { + he->size += hec->size; + hec->attributes = VMM_HE_UNUSED; } } + hec = (HeapEntry *)hec->link; + if (!hec) + break; + } +} + + +// This function retrieves more physical memory for the heap +int vmm_moreCore(dword bytes) +{ + dword pages = (bytes >> 12) + 1; + bytes = pages << 12; + HeapEntry *he = vmm_getFirstHoleHeapEntry(bytes); + dword virt = he->base; + for (; pages > 0; pages--) + { + dword phys = (dword)mm_palloc(); + if (!phys) + return 1; + vmm_map1(virt, phys); + virt += 4096; + } + if (he->size == bytes) + { + he->attributes = VMM_HE_FREE; + vmm_coalesceHeapEntry(he); + } + else + { + HeapEntry *nhe = vmm_nextHeapEntry(); + nhe->base = he->base; + nhe->size = bytes; + nhe->attributes = VMM_HE_FREE; + he->base += bytes; + he->size -= bytes; + vmm_coalesceHeapEntry(nhe); + } + return 0; +} + + +// This function returns the next available heap entry, creates more entries if we are running low +HeapEntry *vmm_nextHeapEntry() +{ + if (vmm_heapEntriesLeft() < 10) + vmm_addHeapEntryBlock(); + return vmm_getFirstUnusedHeapEntry(); +} + + +// This function creates a new block (page) of heap entries (256) +void vmm_addHeapEntryBlock() +{ + HeapEntry *he = vmm_getFirstHoleHeapEntry(4096); + HeapEntry *newBlock = vmm_getFirstUnusedHeapEntry(); + dword heb = (dword)mm_palloc(); + vmm_map1(he->base, heb); + vmm_heb_init((HeapEntryBlock *)he->base); + HeapEntry *lhe = vmm_getLastHeapEntry(); + if (he->size == 4096) + { + he->attributes = VMM_HE_HEB; + lhe->link = (dword)he->base; + } + else + { + newBlock->base = he->base; + newBlock->size = 4096; + newBlock->attributes = VMM_HE_HEB; + he->base += 4096; + he->size -= 4096; + lhe->link = (dword)newBlock->base; + } + return; +} + + +// This function returns the last heap entry in the linked list, useful for setting +// its link field to point to the first entry of a newly allocated list +HeapEntry *vmm_getLastHeapEntry() +{ + HeapEntry *he = firstHeapEntry; + for (;;) + { + if (he->link == 0) + return he; + he = (HeapEntry *)he->link; + } +} + + +// This function returns the first heap entry corresponding to a memory "hole" +HeapEntry *vmm_getFirstHoleHeapEntry(dword minBytes) +{ + HeapEntry *he = firstHeapEntry; + for (;;) + { + if ((he->attributes == VMM_HE_HOLE) && (he->size >= minBytes)) + return he; + he = (HeapEntry *)he->link; + if (!he) + break; + } + return 0; +} + + +// This function returns the first heap entry that is not being used +HeapEntry *vmm_getFirstUnusedHeapEntry() +{ + HeapEntry *he = firstHeapEntry; + for (;;) + { + if (he->attributes == VMM_HE_UNUSED) + return he; + he = (HeapEntry *)he->link; + if (!he) + break; + } + return 0; +} + + +// This function returns the number of heap entries available for use +dword vmm_heapEntriesLeft() +{ + HeapEntry *he = firstHeapEntry; + dword entries = 0; + for (;;) + { + if (he->attributes == VMM_HE_UNUSED) + entries++; + he = (HeapEntry *)he->link; + if (!he) + break; + } + return entries; +} + + +// This function "frees" an area of memory previously allocated with malloc() +int free(void *ptr) +{ + HeapEntry *he = vmm_getHeapEntryByBase((dword)ptr); + if (!he) + return 1; //a heap entry starting at the given address was not found + he->attributes = VMM_HE_FREE; + vmm_coalesceHeapEntry(he); + return 0; +} + + +// This function scans the heap entry linked list for an entry that begins at the given address +HeapEntry *vmm_getHeapEntryByBase(dword base) +{ + HeapEntry *he = firstHeapEntry; + for (;;) + { + if (he->base == base) + return he; + he = (HeapEntry *)he->link; + if (!he) + break; } return 0; } -int free(void *ptr) -{ - - - - -} - - - diff --git a/vmm.h b/vmm.h index a94b66e..82d349f 100644 --- a/vmm.h +++ b/vmm.h @@ -2,7 +2,7 @@ // Author: Josh Holtrop // Date: 09/30/03 // Rewritten from scratch: 12/23/03 -// Modified: 12/29/03 +// Modified: 12/30/03 #define VMM_HE_UNUSED 0 //available entry @@ -11,6 +11,7 @@ #define VMM_HE_HOLE 3 //a "hole" (unmapped) section of virtual memory #define VMM_HE_HEB 4 //HeapEntryBlock +#define VMM_MALLOC_GRANULARITY 4 //granularity for all memory requests typedef struct { dword base; //virtual base address @@ -33,9 +34,19 @@ void vmm_mapn(dword virt, dword physical, dword n); void vmm_unmap1(dword virt); void vmm_unmapn(dword virt, dword n); void vmm_heb_init(HeapEntryBlock *heb); +void *vmm_getFreeChunk(dword bytes); +HeapEntry *vmm_nextHeapEntry(); +dword vmm_heapEntriesLeft(); +HeapEntry *vmm_getLastHeapEntry(); +HeapEntry *vmm_getFirstUnusedHeapEntry(); +HeapEntry *vmm_getFirstHoleHeapEntry(dword minBytes); +void vmm_addHeapEntryBlock(); +int vmm_moreCore(dword bytes); +void vmm_coalesceHeapEntry(HeapEntry *he); +HeapEntry *vmm_getHeapEntryByBase(dword base); -HeapEntry *firstHeapEntry = (HeapEntry *)0xD0000000; +HeapEntry *firstHeapEntry = (HeapEntry *)0xD0000000; //this is where heap memory starts