diff --git a/kernel/page.c b/kernel/page.c new file mode 100644 index 0000000..1d80a6f --- /dev/null +++ b/kernel/page.c @@ -0,0 +1,107 @@ +/* +Copyright (C) 2015-2019 The University of Notre Dame +This software is distributed under the GNU General Public License. +See the file LICENSE for details. +*/ + +#include "console.h" +#include "kernel/types.h" +#include "page.h" +#include "string.h" +#include "memorylayout.h" +#include "kernelcore.h" + +static uint32_t pages_free = 0; +static uint32_t pages_total = 0; + +static uint32_t *freemap = 0; +static uint32_t freemap_bits = 0; +static uint32_t freemap_bytes = 0; +static uint32_t freemap_cells = 0; +static uint32_t freemap_pages = 0; + +static void *main_memory_start = (void *) MAIN_MEMORY_START; + +#define CELL_BITS (8*sizeof(*freemap)) + +void page_init() +{ + int i; + + pages_total = (total_memory * 1024 * 1024 - MAIN_MEMORY_START) / PAGE_SIZE; + pages_free = pages_total; + printf("memory: %d MB (%d KB) total\n", (pages_free * PAGE_SIZE) / MEGA, (pages_free * PAGE_SIZE) / KILO); + + freemap = main_memory_start; + freemap_bits = pages_total; + freemap_bytes = 1 + freemap_bits / 8; + freemap_cells = 1 + freemap_bits / CELL_BITS; + freemap_pages = 1 + freemap_bytes / PAGE_SIZE; + + printf("memory: %d bits %d bytes %d cells %d pages\n", freemap_bits, freemap_bytes, freemap_cells, freemap_pages); + + memset(freemap, 0xff, freemap_bytes); + for(i = 0; i < freemap_pages; i++) + page_alloc(0); + + // This is ahack that I don't understand yet. + // vmware doesn't like the use of a particular page + // close to 1MB, but what it is used for I don't know. + + freemap[0] = 0x0; + + printf("memory: %d MB (%d KB) available\n", (pages_free * PAGE_SIZE) / MEGA, (pages_free * PAGE_SIZE) / KILO); +} + +void page_stats( uint32_t *nfree, uint32_t *ntotal ) +{ + *nfree = pages_free; + *ntotal = pages_total; +} + +void *page_alloc(bool zeroit) +{ + uint32_t i, j; + uint32_t cellmask; + uint32_t pagenumber; + void *pageaddr; + + if(!freemap) { + printf("memory: not initialized yet!\n"); + return 0; + } + + for(i = 0; i < freemap_cells; i++) { + if(freemap[i] != 0) { + for(j = 0; j < CELL_BITS; j++) { + cellmask = (1 << j); + if(freemap[i] & cellmask) { + freemap[i] &= ~cellmask; + pagenumber = i * CELL_BITS + j; + pageaddr = (pagenumber << PAGE_BITS) + main_memory_start; + if(zeroit) + memset(pageaddr, 0, PAGE_SIZE); + pages_free--; + //printf("page: alloc %d\n",pages_free); + return pageaddr; + } + } + } + } + + printf("memory: WARNING: everything allocated\n"); + halt(); + + return 0; +} + +void page_free(void *pageaddr) +{ + uint32_t pagenumber = (pageaddr - main_memory_start) >> PAGE_BITS; + uint32_t cellnumber = pagenumber / CELL_BITS; + uint32_t celloffset = pagenumber % CELL_BITS; + uint32_t cellmask = (1 << celloffset); + freemap[cellnumber] |= cellmask; + pages_free++; + //printf("page: free %d\n",pages_free); +}