2 * Physical memory allocation
3 * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
4 * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
7 * This is free software. You are permitted to use,
8 * redistribute, and modify it as specified in the file "COPYING".
11 #include <geekos/defs.h>
12 #include <geekos/ktypes.h>
13 #include <geekos/kassert.h>
14 #include <geekos/bootinfo.h>
15 #include <geekos/gdt.h>
16 #include <geekos/screen.h>
17 #include <geekos/int.h>
18 #include <geekos/malloc.h>
19 #include <geekos/string.h>
20 #include <geekos/mem.h>
22 #include <geekos/serial.h>
23 #include <geekos/debug.h>
25 /* ----------------------------------------------------------------------
27 * ---------------------------------------------------------------------- */
30 * List of Page structures representing each page of physical memory.
32 struct Page* g_pageList;
35 * Number of pages currently available on the freelist.
37 uint_t g_freePageCount = 0;
39 /* ----------------------------------------------------------------------
40 * Private data and functions
41 * ---------------------------------------------------------------------- */
46 extern int debugFaults;
47 #define Debug(args...) if (debugFaults) Print(args)
50 * List of pages available for allocation.
52 static struct Page_List s_freeList;
55 * Total number of physical pages.
57 int unsigned s_numPages;
60 * Add a range of pages to the inventory of physical memory.
62 static void Add_Page_Range(ulong_t start, ulong_t end, int flags)
66 PrintBoth("Start: %u, End: %u (Type=0x%.4x)\n", (unsigned int)start, (unsigned int)end, flags);
68 KASSERT(Is_Page_Multiple(start));
69 KASSERT(Is_Page_Multiple(end));
72 //Print("Adding %lu pages\n", (end - start) / PAGE_SIZE);
74 for (addr = start; addr < end; addr += PAGE_SIZE) {
75 // Print("Adding Page at %u\n", (unsigned int)addr);
76 struct Page *page = Get_Page(addr);
80 if (flags == PAGE_AVAIL) {
81 /* Add the page to the freelist */
82 Add_To_Back_Of_Page_List(&s_freeList, page);
84 /* Update free page count */
87 Set_Next_In_Page_List(page, 0);
88 Set_Prev_In_Page_List(page, 0);
92 // Print("%d pages now in freelist\n", g_freePageCount);
96 /* ----------------------------------------------------------------------
98 * ---------------------------------------------------------------------- */
101 * The linker defines this symbol to indicate the end of
102 * the executable image.
107 * Initialize memory management data structures.
108 * Enables the use of Alloc_Page() and Free_Page() functions.
110 void Init_Mem(struct Boot_Info* bootInfo)
112 ulong_t numPages = bootInfo->memSizeKB >> 2;
113 ulong_t endOfMem = numPages * PAGE_SIZE;
114 unsigned numPageListBytes = sizeof(struct Page) * numPages;
115 ulong_t pageListAddr;
124 KASSERT(bootInfo->memSizeKB > 0);
128 * Before we do anything, switch from setup.asm's temporary GDT
129 * to the kernel's permanent GDT.
134 PrintBoth("Total Memory Size: %u MBytes\n", bootInfo->memSizeKB/1024);
135 PrintBoth("Page List Size: %u bytes\n", numPageListBytes);
139 * bios area (1 page reserved)
140 * kernel_thread_obj (1 page)
141 * kernel_stack (1 page)
143 * start - end: kernel
145 * ISA_HOLE_START - ISA_HOLE_END: hardware
147 * VM Guest (variable pages)
149 * Page List (variable pages)
150 * Available Memory for VMM (4096 pages)
151 * VM Memory (everything else)
154 kernEnd = Round_Up_To_Page((ulong_t)&end);
155 PrintBoth("Kernel End=%lx\n", kernEnd);
158 /* ************************************************************************************** */
159 /* If we have dynamic loading of the guest kernel, we should put the relocation code here */
160 /* ************************************************************************************** */
162 guestEnd = Round_Up_To_Page(ISA_HOLE_END + bootInfo->guest_size);
164 heapEnd = Round_Up_To_Page(heapAddr + KERNEL_HEAP_SIZE);
165 pageListAddr = heapEnd;
166 pageListEnd = Round_Up_To_Page(pageListAddr + numPageListBytes);
167 /* Global variables */
168 // These must be set before we can call Add_Page_Range..
169 g_pageList = (struct Page*) pageListAddr;
170 s_numPages = numPages;
172 vmmMemEnd = Round_Up_To_Page(pageListEnd + VMM_AVAIL_MEM_SIZE);
177 Add_Page_Range(0, PAGE_SIZE, PAGE_UNUSED); // BIOS area
178 Add_Page_Range(PAGE_SIZE, PAGE_SIZE * 3, PAGE_ALLOCATED); // Intial kernel thread obj + stack
179 Add_Page_Range(PAGE_SIZE * 3, KERNEL_START_ADDR, PAGE_AVAIL); // Available space
180 Add_Page_Range(KERNEL_START_ADDR, kernEnd, PAGE_KERN); // VMM Kernel
181 Add_Page_Range(kernEnd, ISA_HOLE_START, PAGE_AVAIL); // Available Space
182 Add_Page_Range(ISA_HOLE_START, ISA_HOLE_END, PAGE_HW); // Hardware ROMs
183 Add_Page_Range(ISA_HOLE_END, guestEnd, PAGE_VM); // Guest kernel location
184 Add_Page_Range(heapAddr, heapEnd, PAGE_HEAP); // Heap
185 Add_Page_Range(pageListAddr, pageListEnd, PAGE_KERN); // Page List
186 Add_Page_Range(pageListEnd, vmmMemEnd, PAGE_AVAIL); // Available VMM memory
187 Add_Page_Range(vmmMemEnd, endOfMem, PAGE_VM); // Memory allocated to the VM
191 /* Initialize the kernel heap */
192 Init_Heap(heapAddr, KERNEL_HEAP_SIZE);
194 PrintBoth("%uKB memory detected, %u pages in freelist, %d bytes in kernel heap\n",
195 bootInfo->memSizeKB, g_freePageCount, KERNEL_HEAP_SIZE);
197 PrintBoth("Memory Layout:\n");
198 PrintBoth("%x to %x - BIOS AREA\n", 0, PAGE_SIZE - 1);
199 PrintBoth("%x to %x - KERNEL_THREAD_OBJ\n", PAGE_SIZE, PAGE_SIZE * 2 - 1);
200 PrintBoth("%x to %x - KERNEL_STACK\n", PAGE_SIZE * 2, PAGE_SIZE * 3 - 1);
201 PrintBoth("%lx to %x - FREE\n", PAGE_SIZE * 3, KERNEL_START_ADDR - 1);
202 PrintBoth("%x to %x - KERNEL CODE\n", KERNEL_START_ADDR, kernEnd - 1);
203 PrintBoth("%lx to %x - FREE\n", kernEnd, ISA_HOLE_START - 1);
204 PrintBoth("%x to %x - ISA_HOLE\n", ISA_HOLE_START, ISA_HOLE_END - 1);
205 PrintBoth("%x to %x - VM_KERNEL\n", ISA_HOLE_END, guestEnd - 1);
206 PrintBoth("%x to %x - KERNEL HEAP\n", heapAddr, heapEnd - 1);
207 PrintBoth("%lx to %lx - PAGE LIST\n", pageListAddr, pageListEnd - 1);
208 PrintBoth("%lx to %x - FREE\n", pageListEnd, vmmMemEnd - 1);
209 PrintBoth("%lx to %x - GUEST_MEMORY\n", vmmMemEnd, endOfMem - 1);
213 * Initialize the .bss section of the kernel executable image.
217 extern char BSS_START, BSS_END;
219 /* Fill .bss with zeroes */
220 memset(&BSS_START, '\0', &BSS_END - &BSS_START);
221 PrintBoth("BSS Inited, BSS_START=%x, BSS_END=%x\n",BSS_START,BSS_END);
225 * Allocate a page of physical memory.
227 void* Alloc_Page(void)
232 bool iflag = Begin_Int_Atomic();
234 /* See if we have a free page */
235 if (!Is_Page_List_Empty(&s_freeList)) {
236 /* Remove the first page on the freelist. */
237 page = Get_Front_Of_Page_List(&s_freeList);
238 KASSERT((page->flags & PAGE_ALLOCATED) == 0);
239 Remove_From_Front_Of_Page_List(&s_freeList);
241 /* Mark page as having been allocated. */
242 page->flags |= PAGE_ALLOCATED;
244 result = (void*) Get_Page_Address(page);
247 End_Int_Atomic(iflag);
253 * Free a page of physical memory.
255 void Free_Page(void* pageAddr)
257 ulong_t addr = (ulong_t) pageAddr;
261 iflag = Begin_Int_Atomic();
263 KASSERT(Is_Page_Multiple(addr));
265 /* Get the Page object for this page */
266 page = Get_Page(addr);
267 KASSERT((page->flags & PAGE_ALLOCATED) != 0);
269 /* Clear the allocation bit */
270 page->flags &= ~(PAGE_ALLOCATED);
272 /* Put the page back on the freelist */
273 Add_To_Back_Of_Page_List(&s_freeList, page);
276 End_Int_Atomic(iflag);