/* * Physical memory allocation * Copyright (c) 2001,2003,2004 David H. Hovemeyer * Copyright (c) 2003, Jeffrey K. Hollingsworth * $Revision: 1.7 $ * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "COPYING". */ #include #include #include #include #include #include #include #include #include #include #include #include /* ---------------------------------------------------------------------- * Global data * ---------------------------------------------------------------------- */ /* * List of Page structures representing each page of physical memory. */ struct Page* g_pageList; /* * 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, End: %u (Type=0x%.4x)\n", (unsigned int)start, (unsigned int)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 guestEnd; ulong_t heapAddr; ulong_t heapEnd; ulong_t vmmMemEnd; 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 Size: %u bytes\n", numPageListBytes); /* Memory Layout: * bios area (1 page reserved) * kernel_thread_obj (1 page) * kernel_stack (1 page) * available space * start - end: kernel * available space * ISA_HOLE_START - ISA_HOLE_END: hardware * EXTENDED_MEMORY: * VM Guest (variable pages) * Heap (512 Pages) * Page List (variable pages) * Available Memory for VMM (4096 pages) * VM Memory (everything else) */ kernEnd = Round_Up_To_Page((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 */ /* ************************************************************************************** */ guestEnd = Round_Up_To_Page(ISA_HOLE_END + bootInfo->guest_size); heapAddr = guestEnd; 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); /* * the disgusting way to get at the memory assigned to a VM */ vm_range_start = vmmMemEnd; vm_range_end = endOfMem; guest_kernel_start = ISA_HOLE_END; guest_kernel_end = guestEnd; 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, KERNEL_START_ADDR, PAGE_AVAIL); // Available space Add_Page_Range(KERNEL_START_ADDR, kernEnd, PAGE_KERN); // VMM Kernel Add_Page_Range(kernEnd, ISA_HOLE_START, PAGE_AVAIL); // Available Space Add_Page_Range(ISA_HOLE_START, ISA_HOLE_END, PAGE_HW); // Hardware ROMs Add_Page_Range(ISA_HOLE_END, 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 Add_Page_Range(vmmMemEnd, endOfMem, PAGE_VM); // 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, KERNEL_START_ADDR - 1); PrintBoth("%x to %x - KERNEL CODE\n", KERNEL_START_ADDR, kernEnd - 1); PrintBoth("%lx to %x - FREE\n", kernEnd, ISA_HOLE_START - 1); PrintBoth("%x to %x - ISA_HOLE\n", ISA_HOLE_START, ISA_HOLE_END - 1); PrintBoth("%x to %x - VM_KERNEL\n", ISA_HOLE_END, 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); PrintBoth("%lx to %x - GUEST_MEMORY\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); }