Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / geekos / mem.c
diff --git a/geekos/src/geekos/mem.c b/geekos/src/geekos/mem.c
new file mode 100644 (file)
index 0000000..5c8e916
--- /dev/null
@@ -0,0 +1,356 @@
+ /*
+ * Physical memory allocation
+ * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
+ * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * $Revision: 1.13 $
+ * 
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+#include <geekos/defs.h>
+#include <geekos/ktypes.h>
+#include <geekos/kassert.h>
+#include <geekos/bootinfo.h>
+#include <geekos/gdt.h>
+#include <geekos/screen.h>
+#include <geekos/int.h>
+#include <geekos/malloc.h>
+#include <geekos/string.h>
+#include <geekos/mem.h>
+
+#include <geekos/serial.h>
+#include <geekos/debug.h>
+
+
+/* ----------------------------------------------------------------------
+ * Global data
+ * ---------------------------------------------------------------------- */
+
+/*
+ * List of Page structures representing each page of physical memory.
+ */
+struct Page* g_pageList;
+
+void * g_ramdiskImage;
+ulong_t s_ramdiskSize;
+
+
+/*
+ * Number of pages currently available on the freelist.
+ */
+uint_t g_freePageCount = 0;
+
+
+
+/* 
+ *  the disgusting way to get at the memory assigned to a VM
+ */
+extern ulong_t vm_range_start;
+extern ulong_t vm_range_end;
+extern ulong_t guest_kernel_start;
+extern ulong_t guest_kernel_end;
+
+
+
+/* ----------------------------------------------------------------------
+ * Private data and functions
+ * ---------------------------------------------------------------------- */
+
+/*
+ * Defined in paging.c
+ */
+extern int debugFaults;
+#define Debug(args...) if (debugFaults) Print(args)
+
+/*
+ * List of pages available for allocation.
+ */
+static struct Page_List s_freeList;
+
+/*
+ * Total number of physical pages.
+ */
+int unsigned s_numPages;
+
+
+
+
+/*
+ * Add a range of pages to the inventory of physical memory.
+ */
+static void Add_Page_Range(ulong_t start, ulong_t end, int flags)
+{
+    ulong_t addr;
+
+    PrintBoth("Start: %u (0x%x), End: %u(0x%x)  (Type=0x%.4x)\n", (unsigned int)start, start, (unsigned int)end, end, flags);
+
+    KASSERT(Is_Page_Multiple(start));
+    KASSERT(Is_Page_Multiple(end));
+    KASSERT(start < end);
+
+    //Print("Adding %lu pages\n", (end - start) / PAGE_SIZE);
+
+    for (addr = start; addr < end; addr += PAGE_SIZE) {
+      //      Print("Adding Page at %u\n", (unsigned int)addr);
+       struct Page *page = Get_Page(addr);
+
+       page->flags = flags;
+
+       if (flags == PAGE_AVAIL) {
+           /* Add the page to the freelist */
+           Add_To_Back_Of_Page_List(&s_freeList, page);
+
+           /* Update free page count */
+           ++g_freePageCount;
+       } else {
+           Set_Next_In_Page_List(page, 0);
+           Set_Prev_In_Page_List(page, 0);
+       }
+
+    }
+    //   Print("%d pages now in freelist\n", g_freePageCount);
+
+}
+
+/* ----------------------------------------------------------------------
+ * Public functions
+ * ---------------------------------------------------------------------- */
+
+/*
+ * The linker defines this symbol to indicate the end of
+ * the executable image.
+ */
+extern char end;
+
+/*
+ * Initialize memory management data structures.
+ * Enables the use of Alloc_Page() and Free_Page() functions.
+ */
+void Init_Mem(struct Boot_Info* bootInfo)
+{
+    ulong_t numPages = bootInfo->memSizeKB >> 2;
+    ulong_t endOfMem = numPages * PAGE_SIZE;
+    unsigned numPageListBytes = sizeof(struct Page) * numPages;
+    ulong_t pageListAddr;
+    ulong_t pageListEnd;
+    ulong_t kernEnd;
+    ulong_t heapAddr;
+    ulong_t heapEnd;
+    ulong_t vmmMemEnd;
+
+
+    g_ramdiskImage = bootInfo->ramdisk_image;
+    s_ramdiskSize = bootInfo->ramdisk_size;
+    ulong_t initrdAddr = 0;
+    ulong_t initrdEnd = 0;
+
+    
+
+    KASSERT(bootInfo->memSizeKB > 0);
+
+
+    /*
+     * Before we do anything, switch from setup.asm's temporary GDT
+     * to the kernel's permanent GDT.
+     */
+    Init_GDT();
+
+
+    PrintBoth("Total Memory Size: %u MBytes\n", bootInfo->memSizeKB/1024);
+    PrintBoth("Page List (at 0x%x) Size: %u bytes\n", &s_freeList, numPageListBytes);
+
+  
+    /* Memory Layout:
+     * bios area (1 page reserved) 
+     * kernel_thread_obj (1 page)
+     * kernel_stack (1 page)
+     * available space
+     * available space
+     * ISA_HOLE_START - ISA_HOLE_END: hardware
+     * EXTENDED_MEMORY:
+     *        start - end:       kernel
+     *        VM Guest (variable pages)
+     *        Heap (512 Pages)
+     *        Page List (variable pages)
+     *        Available Memory for VMM (4096 pages)
+     *        Ramdisk //Zheng 08/03/2008
+     *        VM Memory (everything else)
+     */
+
+    //kernEnd = Round_Up_To_Page((ulong_t)&end);
+    kernEnd = (ulong_t)&end;
+
+    PrintBoth("Kernel End=%lx\n", kernEnd);
+
+
+    /* ************************************************************************************** */
+    /* If we have dynamic loading of the guest kernel, we should put the relocation code here */
+    /* ************************************************************************************** */
+
+    kernEnd = Round_Up_To_Page(kernEnd);
+    heapAddr = kernEnd;
+    heapEnd = Round_Up_To_Page(heapAddr + KERNEL_HEAP_SIZE);
+    pageListAddr = heapEnd;
+    pageListEnd = Round_Up_To_Page(pageListAddr + numPageListBytes);
+    /* Global variables */
+    // These must be set before we can call Add_Page_Range..
+    g_pageList = (struct Page*) pageListAddr;
+    s_numPages = numPages;
+    /* ** */
+    vmmMemEnd = Round_Up_To_Page(pageListEnd + VMM_AVAIL_MEM_SIZE);
+
+    /*
+     * Zheng 08/03/2008
+     * copy the ramdisk to this area 
+     */
+    if (s_ramdiskSize > 0) {
+      initrdAddr = vmmMemEnd;
+      initrdEnd = Round_Up_To_Page(initrdAddr + s_ramdiskSize);
+      PrintBoth("mem.c(%d) Move ramdisk(%dB) from %x to %x", __LINE__, s_ramdiskSize, g_ramdiskImage, initrdAddr);
+      memcpy((ulong_t *)initrdAddr, (ulong_t *)g_ramdiskImage, s_ramdiskSize);
+      PrintBoth(" done\n");
+      PrintBoth("mem.c(%d) Set 0 to unused bytes in the last ramdisk page from %x to %x", __LINE__, initrdAddr+s_ramdiskSize, initrdEnd);
+      memset((ulong_t *)initrdAddr + s_ramdiskSize, 0, initrdEnd - (initrdAddr + s_ramdiskSize));
+      PrintBoth(" done\n");
+    }
+
+    
+    /* 
+     *  the disgusting way to get at the memory assigned to a VM
+     */
+    
+    //vm_range_start = vmmMemEnd;
+    //vm_range_end = endOfMem;
+    /*
+     * Zheng 08/03/2008
+     */
+    if (s_ramdiskSize > 0) {
+      vm_range_start = initrdEnd;
+      vm_range_end = endOfMem;    
+    }
+
+    Add_Page_Range(0, PAGE_SIZE, PAGE_UNUSED);                        // BIOS area
+    Add_Page_Range(PAGE_SIZE, PAGE_SIZE * 3, PAGE_ALLOCATED);         // Intial kernel thread obj + stack
+    Add_Page_Range(PAGE_SIZE * 3, ISA_HOLE_START, PAGE_AVAIL);     // Available space
+    Add_Page_Range(ISA_HOLE_START, ISA_HOLE_END, PAGE_HW);            // Hardware ROMs
+    Add_Page_Range(KERNEL_START_ADDR, kernEnd, PAGE_KERN);            // VMM Kernel
+    //    Add_Page_Range(guest_kernel_start, guestEnd, PAGE_VM);                  // Guest kernel location
+    Add_Page_Range(heapAddr, heapEnd, PAGE_HEAP);                     // Heap
+    Add_Page_Range(pageListAddr, pageListEnd, PAGE_KERN);             // Page List 
+    Add_Page_Range(pageListEnd, vmmMemEnd, PAGE_AVAIL);               // Available VMM memory
+
+
+    if (s_ramdiskSize > 0) {
+      /*
+       * Zheng 08/03/2008
+       */
+      Add_Page_Range(vmmMemEnd, initrdEnd, PAGE_ALLOCATED);              //Ramdisk memory area      
+      //    Add_Page_Range(vmmMemEnd, endOfMem, PAGE_VM);                // Memory allocated to the VM
+      // Until we get a more intelligent memory allocator
+      Add_Page_Range(initrdEnd, endOfMem, PAGE_AVAIL);                   // Memory allocated to the VM
+    } else {
+      Add_Page_Range(vmmMemEnd, endOfMem, PAGE_AVAIL);                   // Memory allocated to the VM
+    }
+
+    /* Initialize the kernel heap */
+    Init_Heap(heapAddr, KERNEL_HEAP_SIZE);
+
+    PrintBoth("%uKB memory detected, %u pages in freelist, %d bytes in kernel heap\n",
+       bootInfo->memSizeKB, g_freePageCount, KERNEL_HEAP_SIZE);
+
+    PrintBoth("Memory Layout:\n");
+    PrintBoth("%x to %x - BIOS AREA\n", 0, PAGE_SIZE - 1);
+    PrintBoth("%x to %x - KERNEL_THREAD_OBJ\n", PAGE_SIZE, PAGE_SIZE * 2 - 1);
+    PrintBoth("%x to %x - KERNEL_STACK\n", PAGE_SIZE * 2, PAGE_SIZE * 3 - 1);
+    PrintBoth("%lx to %x - FREE\n", PAGE_SIZE * 3, ISA_HOLE_START - 1);
+    PrintBoth("%x to %x - ISA_HOLE\n", ISA_HOLE_START, ISA_HOLE_END - 1);
+    PrintBoth("%x to %x - KERNEL CODE + VM_KERNEL\n", KERNEL_START_ADDR, kernEnd - 1);
+    //    PrintBoth("%x to %x - VM_KERNEL\n", kernEnd, guestEnd - 1);
+    PrintBoth("%x to %x - KERNEL HEAP\n", heapAddr, heapEnd - 1);
+    PrintBoth("%lx to %lx - PAGE LIST\n", pageListAddr, pageListEnd - 1);
+    PrintBoth("%lx to %x - FREE\n", pageListEnd, vmmMemEnd - 1);
+
+
+    if (s_ramdiskSize > 0) {
+      /*
+       * Zheng 08/03/2008
+       */
+      PrintBoth("%lx to %x - RAMDISK\n", vmmMemEnd, initrdEnd - 1);
+      
+      PrintBoth("%lx to %x - GUEST_MEMORY (also free)\n", initrdEnd, endOfMem - 1);
+    } else {
+      PrintBoth("%lx to %x - GUEST_MEMORY (also free)\n", vmmMemEnd, endOfMem - 1);
+    }
+    
+}
+
+/*
+ * Initialize the .bss section of the kernel executable image.
+ */
+void Init_BSS(void)
+{
+    extern char BSS_START, BSS_END;
+
+    /* Fill .bss with zeroes */
+    memset(&BSS_START, '\0', &BSS_END - &BSS_START);
+    // screen is not inited yet - PAD
+    // PrintBoth("BSS Inited, BSS_START=%x, BSS_END=%x\n",BSS_START,BSS_END);
+}
+
+/*
+ * Allocate a page of physical memory.
+ */
+void* Alloc_Page(void)
+{
+    struct Page* page;
+    void *result = 0;
+
+    bool iflag = Begin_Int_Atomic();
+
+    /* See if we have a free page */
+    if (!Is_Page_List_Empty(&s_freeList)) {
+       /* Remove the first page on the freelist. */
+       page = Get_Front_Of_Page_List(&s_freeList);
+       KASSERT((page->flags & PAGE_ALLOCATED) == 0);
+       Remove_From_Front_Of_Page_List(&s_freeList);
+
+       /* Mark page as having been allocated. */
+       page->flags |= PAGE_ALLOCATED;
+       g_freePageCount--;
+       result = (void*) Get_Page_Address(page);
+    }
+
+    End_Int_Atomic(iflag);
+
+    return result;
+}
+
+/*
+ * Free a page of physical memory.
+ */
+void Free_Page(void* pageAddr)
+{
+    ulong_t addr = (ulong_t) pageAddr;
+    struct Page* page;
+    bool iflag;
+
+    iflag = Begin_Int_Atomic();
+
+    KASSERT(Is_Page_Multiple(addr));
+
+    /* Get the Page object for this page */
+    page = Get_Page(addr);
+    KASSERT((page->flags & PAGE_ALLOCATED) != 0);
+
+    /* Clear the allocation bit */
+    page->flags &= ~(PAGE_ALLOCATED);
+
+    /* Put the page back on the freelist */
+    Add_To_Back_Of_Page_List(&s_freeList, page);
+    g_freePageCount++;
+
+    End_Int_Atomic(iflag);
+}