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>
26 /* ----------------------------------------------------------------------
28 * ---------------------------------------------------------------------- */
31 * List of Page structures representing each page of physical memory.
33 struct Page* g_pageList;
36 * Number of pages currently available on the freelist.
38 uint_t g_freePageCount = 0;
43 * the disgusting way to get at the memory assigned to a VM
45 extern ulong_t vm_range_start;
46 extern ulong_t vm_range_end;
47 extern ulong_t guest_kernel_start;
48 extern ulong_t guest_kernel_end;
52 /* ----------------------------------------------------------------------
53 * Private data and functions
54 * ---------------------------------------------------------------------- */
59 extern int debugFaults;
60 #define Debug(args...) if (debugFaults) Print(args)
63 * List of pages available for allocation.
65 static struct Page_List s_freeList;
68 * Total number of physical pages.
70 int unsigned s_numPages;
76 * Add a range of pages to the inventory of physical memory.
78 static void Add_Page_Range(ulong_t start, ulong_t end, int flags)
82 PrintBoth("Start: %u, End: %u (Type=0x%.4x)\n", (unsigned int)start, (unsigned int)end, flags);
84 KASSERT(Is_Page_Multiple(start));
85 KASSERT(Is_Page_Multiple(end));
88 //Print("Adding %lu pages\n", (end - start) / PAGE_SIZE);
90 for (addr = start; addr < end; addr += PAGE_SIZE) {
91 // Print("Adding Page at %u\n", (unsigned int)addr);
92 struct Page *page = Get_Page(addr);
96 if (flags == PAGE_AVAIL) {
97 /* Add the page to the freelist */
98 Add_To_Back_Of_Page_List(&s_freeList, page);
100 /* Update free page count */
103 Set_Next_In_Page_List(page, 0);
104 Set_Prev_In_Page_List(page, 0);
108 // Print("%d pages now in freelist\n", g_freePageCount);
112 /* ----------------------------------------------------------------------
114 * ---------------------------------------------------------------------- */
117 * The linker defines this symbol to indicate the end of
118 * the executable image.
123 * Initialize memory management data structures.
124 * Enables the use of Alloc_Page() and Free_Page() functions.
126 void Init_Mem(struct Boot_Info* bootInfo)
128 ulong_t numPages = bootInfo->memSizeKB >> 2;
129 ulong_t endOfMem = numPages * PAGE_SIZE;
130 unsigned numPageListBytes = sizeof(struct Page) * numPages;
131 ulong_t pageListAddr;
140 KASSERT(bootInfo->memSizeKB > 0);
144 * Before we do anything, switch from setup.asm's temporary GDT
145 * to the kernel's permanent GDT.
150 PrintBoth("Total Memory Size: %u MBytes\n", bootInfo->memSizeKB/1024);
151 PrintBoth("Page List Size: %u bytes\n", numPageListBytes);
155 * bios area (1 page reserved)
156 * kernel_thread_obj (1 page)
157 * kernel_stack (1 page)
159 * start - end: kernel
161 * ISA_HOLE_START - ISA_HOLE_END: hardware
163 * VM Guest (variable pages)
165 * Page List (variable pages)
166 * Available Memory for VMM (4096 pages)
167 * VM Memory (everything else)
170 kernEnd = Round_Up_To_Page((ulong_t)&end);
171 PrintBoth("Kernel End=%lx\n", kernEnd);
174 /* ************************************************************************************** */
175 /* If we have dynamic loading of the guest kernel, we should put the relocation code here */
176 /* ************************************************************************************** */
178 guestEnd = Round_Up_To_Page(ISA_HOLE_END + bootInfo->guest_size);
180 heapEnd = Round_Up_To_Page(heapAddr + KERNEL_HEAP_SIZE);
181 pageListAddr = heapEnd;
182 pageListEnd = Round_Up_To_Page(pageListAddr + numPageListBytes);
183 /* Global variables */
184 // These must be set before we can call Add_Page_Range..
185 g_pageList = (struct Page*) pageListAddr;
186 s_numPages = numPages;
188 vmmMemEnd = Round_Up_To_Page(pageListEnd + VMM_AVAIL_MEM_SIZE);
192 * the disgusting way to get at the memory assigned to a VM
194 vm_range_start = vmmMemEnd;
195 vm_range_end = endOfMem;
196 guest_kernel_start = ISA_HOLE_END;
197 guest_kernel_end = guestEnd;
199 Add_Page_Range(0, PAGE_SIZE, PAGE_UNUSED); // BIOS area
200 Add_Page_Range(PAGE_SIZE, PAGE_SIZE * 3, PAGE_ALLOCATED); // Intial kernel thread obj + stack
201 Add_Page_Range(PAGE_SIZE * 3, KERNEL_START_ADDR, PAGE_AVAIL); // Available space
202 Add_Page_Range(KERNEL_START_ADDR, kernEnd, PAGE_KERN); // VMM Kernel
203 Add_Page_Range(kernEnd, ISA_HOLE_START, PAGE_AVAIL); // Available Space
204 Add_Page_Range(ISA_HOLE_START, ISA_HOLE_END, PAGE_HW); // Hardware ROMs
205 Add_Page_Range(ISA_HOLE_END, guestEnd, PAGE_VM); // Guest kernel location
206 Add_Page_Range(heapAddr, heapEnd, PAGE_HEAP); // Heap
207 Add_Page_Range(pageListAddr, pageListEnd, PAGE_KERN); // Page List
208 Add_Page_Range(pageListEnd, vmmMemEnd, PAGE_AVAIL); // Available VMM memory
209 Add_Page_Range(vmmMemEnd, endOfMem, PAGE_VM); // Memory allocated to the VM
213 /* Initialize the kernel heap */
214 Init_Heap(heapAddr, KERNEL_HEAP_SIZE);
216 PrintBoth("%uKB memory detected, %u pages in freelist, %d bytes in kernel heap\n",
217 bootInfo->memSizeKB, g_freePageCount, KERNEL_HEAP_SIZE);
219 PrintBoth("Memory Layout:\n");
220 PrintBoth("%x to %x - BIOS AREA\n", 0, PAGE_SIZE - 1);
221 PrintBoth("%x to %x - KERNEL_THREAD_OBJ\n", PAGE_SIZE, PAGE_SIZE * 2 - 1);
222 PrintBoth("%x to %x - KERNEL_STACK\n", PAGE_SIZE * 2, PAGE_SIZE * 3 - 1);
223 PrintBoth("%lx to %x - FREE\n", PAGE_SIZE * 3, KERNEL_START_ADDR - 1);
224 PrintBoth("%x to %x - KERNEL CODE\n", KERNEL_START_ADDR, kernEnd - 1);
225 PrintBoth("%lx to %x - FREE\n", kernEnd, ISA_HOLE_START - 1);
226 PrintBoth("%x to %x - ISA_HOLE\n", ISA_HOLE_START, ISA_HOLE_END - 1);
227 PrintBoth("%x to %x - VM_KERNEL\n", ISA_HOLE_END, guestEnd - 1);
228 PrintBoth("%x to %x - KERNEL HEAP\n", heapAddr, heapEnd - 1);
229 PrintBoth("%lx to %lx - PAGE LIST\n", pageListAddr, pageListEnd - 1);
230 PrintBoth("%lx to %x - FREE\n", pageListEnd, vmmMemEnd - 1);
231 PrintBoth("%lx to %x - GUEST_MEMORY\n", vmmMemEnd, endOfMem - 1);
235 * Initialize the .bss section of the kernel executable image.
239 extern char BSS_START, BSS_END;
241 /* Fill .bss with zeroes */
242 memset(&BSS_START, '\0', &BSS_END - &BSS_START);
243 PrintBoth("BSS Inited, BSS_START=%x, BSS_END=%x\n",BSS_START,BSS_END);
247 * Allocate a page of physical memory.
249 void* Alloc_Page(void)
254 bool iflag = Begin_Int_Atomic();
256 /* See if we have a free page */
257 if (!Is_Page_List_Empty(&s_freeList)) {
258 /* Remove the first page on the freelist. */
259 page = Get_Front_Of_Page_List(&s_freeList);
260 KASSERT((page->flags & PAGE_ALLOCATED) == 0);
261 Remove_From_Front_Of_Page_List(&s_freeList);
263 /* Mark page as having been allocated. */
264 page->flags |= PAGE_ALLOCATED;
266 result = (void*) Get_Page_Address(page);
269 End_Int_Atomic(iflag);
275 * Free a page of physical memory.
277 void Free_Page(void* pageAddr)
279 ulong_t addr = (ulong_t) pageAddr;
283 iflag = Begin_Int_Atomic();
285 KASSERT(Is_Page_Multiple(addr));
287 /* Get the Page object for this page */
288 page = Get_Page(addr);
289 KASSERT((page->flags & PAGE_ALLOCATED) != 0);
291 /* Clear the allocation bit */
292 page->flags &= ~(PAGE_ALLOCATED);
294 /* Put the page back on the freelist */
295 Add_To_Back_Of_Page_List(&s_freeList, page);
298 End_Int_Atomic(iflag);