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.


split the vmm from the internal geekos
[palacios.git] / palacios / src / geekos / mem.c
1 /*
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>
5  * $Revision: 1.3 $
6  * 
7  * This is free software.  You are permitted to use,
8  * redistribute, and modify it as specified in the file "COPYING".
9  */
10
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>
21
22 #include <geekos/vmm_sizes.h>
23 #include <geekos/serial.h>
24 #include <geekos/debug.h>
25
26 /* ----------------------------------------------------------------------
27  * Global data
28  * ---------------------------------------------------------------------- */
29
30 /*
31  * List of Page structures representing each page of physical memory.
32  */
33 struct Page* g_pageList;
34
35 /*
36  * Number of pages currently available on the freelist.
37  */
38 uint_t g_freePageCount = 0;
39
40 /* ----------------------------------------------------------------------
41  * Private data and functions
42  * ---------------------------------------------------------------------- */
43
44 /*
45  * Defined in paging.c
46  */
47 extern int debugFaults;
48 #define Debug(args...) if (debugFaults) Print(args)
49
50 /*
51  * List of pages available for allocation.
52  */
53 static struct Page_List s_freeList;
54
55 /*
56  * Total number of physical pages.
57  */
58 int unsigned s_numPages;
59
60 /*
61  * Add a range of pages to the inventory of physical memory.
62  */
63 static void Add_Page_Range(ulong_t start, ulong_t end, int flags)
64 {
65     ulong_t addr;
66
67     PrintBoth("Start: %u, End: %u\n", (unsigned int)start, (unsigned int)end);
68
69     KASSERT(Is_Page_Multiple(start));
70     KASSERT(Is_Page_Multiple(end));
71     KASSERT(start < end);
72
73     //Print("Adding %lu pages\n", (end - start) / PAGE_SIZE);
74
75     for (addr = start; addr < end; addr += PAGE_SIZE) {
76       //      Print("Adding Page at %u\n", (unsigned int)addr);
77         struct Page *page = Get_Page(addr);
78
79         page->flags = flags;
80
81         if (flags == PAGE_AVAIL) {
82             /* Add the page to the freelist */
83             Add_To_Back_Of_Page_List(&s_freeList, page);
84
85             /* Update free page count */
86             ++g_freePageCount;
87         } else {
88             Set_Next_In_Page_List(page, 0);
89             Set_Prev_In_Page_List(page, 0);
90         }
91
92     }
93     //   Print("%d pages now in freelist\n", g_freePageCount);
94
95 }
96
97 /* ----------------------------------------------------------------------
98  * Public functions
99  * ---------------------------------------------------------------------- */
100
101 /*
102  * The linker defines this symbol to indicate the end of
103  * the executable image.
104  */
105 extern char end;
106
107 /*
108  * Initialize memory management data structures.
109  * Enables the use of Alloc_Page() and Free_Page() functions.
110  */
111 void Init_Mem(struct Boot_Info* bootInfo)
112 {
113     ulong_t numPages = bootInfo->memSizeKB >> 2;
114     //    ulong_t endOfMem = numPages * PAGE_SIZE;
115     unsigned numPageListBytes = sizeof(struct Page) * numPages;
116     ulong_t pageListAddr;
117     ulong_t pageListEnd;
118     ulong_t kernEnd;
119
120
121     KASSERT(bootInfo->memSizeKB > 0);
122
123     if (bootInfo->memSizeKB != TOP_OF_MEM/1024) { 
124       PrintBoth("Kernel compiled for %d KB machine, but machine claims %d KB\n",TOP_OF_MEM/1024,bootInfo->memSizeKB);
125       if (bootInfo->memSizeKB < TOP_OF_MEM/1024) { 
126         PrintBoth("Kernel compiled for more memory than machine has.  Panicking\n");
127         KASSERT(0);
128       }
129     }
130
131     if (0) {
132       // if there is not enough memory between START_OF_VM+VM_SIZE and TOP_OF_MEM
133       // to store the kernel and kernel structures, we need to panick
134       PrintBoth("Kernel is not compiled with sufficient memory above the VM to support the memory\n");
135       KASSERT(0);
136     }
137
138
139     bootInfo->memSizeKB = TOP_OF_MEM / 1024;
140
141     /*
142      * Before we do anything, switch from setup.asm's temporary GDT
143      * to the kernel's permanent GDT.
144      */
145     Init_GDT();
146
147     /*
148      * We'll put the list of Page objects right after the end
149      * of the kernel, and mark it as "kernel".  This will bootstrap
150      * us sufficiently that we can start allocating pages and
151      * keeping track of them.
152      */
153
154     // JRL: This is stupid... 
155     // with large mem sizes the page list overruns into the ISA 
156     // hole. By blind luck this causes an unrelated assertion failure, otherwise
157     // I might never have caught it...
158     // We fix it by moving the page list after the kernel heap...
159     // For now we'll make our own stupid assumption that the mem size
160     // is large enough to accomodate the list in high mem.
161
162     PrintBoth("Total Memory Size: %u MBytes\n", bootInfo->memSizeKB/1024);
163     PrintBoth("VM Start: %x\n",START_OF_VM);
164     PrintBoth("VM End: %x\n",START_OF_VM+VM_SIZE-1);
165     
166
167     PrintBoth("Page struct size: %lu bytes\n", sizeof(struct Page));
168     PrintBoth("Page List Size: %u bytes\n", numPageListBytes);
169
170   
171     //pageListAddr = Round_Up_To_Page((ulong_t) &end);
172     //pageListAddr = Round_Up_To_Page(HIGHMEM_START + KERNEL_HEAP_SIZE);
173
174     // Note that this is now moved to be just above the kernel heap
175     // see defs.h for layout
176     pageListAddr=Round_Up_To_Page(KERNEL_PAGELIST);
177       
178     pageListEnd = Round_Up_To_Page(pageListAddr + numPageListBytes);
179
180     g_pageList = (struct Page*) pageListAddr;
181     //    kernEnd = Round_Up_To_Page(pageListAddr + numPageListBytes);
182     //
183     // PAD - Note: I am changing this so that everything through the end of 
184     // the VM boot package (bioses/vmxassist) is off limits
185     //kernEnd = Round_Up_To_Page((ulong_t) &end);
186     kernEnd = Round_Up_To_Page(VM_BOOT_PACKAGE_END);
187     s_numPages = numPages;
188
189     PrintBoth("Pagelist addr: %p\n", g_pageList);
190     PrintBoth("index: %p\n", &g_pageList[3]);
191     PrintBoth("direct offset: %p\n", g_pageList + (sizeof(struct Page) * 2));
192     //  PrintBoth("Kernel Size=%lx\n", (kernEnd - KERNEL_START_ADDR));
193     // PrintBoth("Kernel Start=%x\n", KERNEL_START_ADDR);
194     PrintBoth("Kernel End=%lx\n", kernEnd);
195     //PrintBoth("end=%x\n", end);
196     PrintBoth("VM Boot Package Start=%x\n", VM_BOOT_PACKAGE_START);
197     PrintBoth("VM Boot Package End=%x\n", VM_BOOT_PACKAGE_END);
198
199     /*
200      * The initial kernel thread and its stack are placed
201      * just beyond the ISA hole.
202      */
203     // This is no longer true
204     // KASSERT(ISA_HOLE_END == KERN_THREAD_OBJ);
205     // instead, 
206     //KASSERT(KERN_THREAD_OBJ==(START_OF_VM+VM_SIZE));
207     //KASSERT(KERN_STACK == KERN_THREAD_OBJ + PAGE_SIZE);
208
209     /*
210      * Memory looks like this:
211      * 0 - start: available (might want to preserve BIOS data area)
212      * start - end: kernel
213      * end - ISA_HOLE_START: available
214      * ISA_HOLE_START - ISA_HOLE_END: used by hardware (and ROM BIOS?)
215      * ISA_HOLE_END - HIGHMEM_START: used by initial kernel thread
216      * HIGHMEM_START - end of memory: available
217      *    (the kernel heap is located at HIGHMEM_START; any unused memory
218      *    beyond that is added to the freelist)
219      */
220
221     // The VM region... 0 .. VM size is out of bounds
222     KASSERT(START_OF_VM==0);
223
224     Add_Page_Range(START_OF_VM, START_OF_VM+VM_SIZE, PAGE_VM);
225     //PrintBoth("hello1\n");
226     // The kernel is still in low memory at this point, in the VM region
227     // Thus we will mark it as kernel use
228     // Add_Page_Range(KERNEL_START_ADDR, kernEnd, PAGE_KERN);
229     
230     
231     //Add_Page_Range(kernEnd, ISA_HOLE_START, PAGE_AVAIL);
232     // ISA hole remains closed (no actual memory)
233     // Add_Page_Range(ISA_HOLE_START, ISA_HOLE_END, PAGE_HW);
234     
235     //Add_Page_Range(ISA_HOLE_END, HIGHMEM_START, PAGE_ALLOCATED);
236     // Add_Page_Range(HIGHMEM_START, HIGHMEM_START + KERNEL_HEAP_SIZE, PAGE_HEAP);
237     //Add_Page_Range(HIGHMEM_START + KERNEL_HEAP_SIZE, endOfMem, PAGE_AVAIL);
238     /* JRL: move page list after kernel heap */
239     
240     //Now, above the VM region...
241
242     // Kernel thread object
243     Add_Page_Range(KERNEL_THREAD_OBJECT,KERNEL_THREAD_OBJECT+KERNEL_THREAD_OBJECT_SIZE,PAGE_ALLOCATED);
244     // Kernel stack
245     Add_Page_Range(KERNEL_STACK,KERNEL_STACK+KERNEL_STACK_SIZE,PAGE_ALLOCATED);
246     // Kernel heap
247     Add_Page_Range(KERNEL_HEAP,KERNEL_HEAP+KERNEL_HEAP_SIZE,PAGE_HEAP);
248     // Kernel page list
249     Add_Page_Range(pageListAddr, pageListEnd, PAGE_KERN);
250     // Free space
251     Add_Page_Range(pageListEnd,Round_Down_To_Page(FINAL_KERNEL_START), PAGE_AVAIL);
252     // The kernel 
253     Add_Page_Range(Round_Down_To_Page(FINAL_KERNEL_START),Round_Up_To_Page(FINAL_VMBOOTEND+1),PAGE_KERN);
254     // The vmbootpackage 
255     // IDT (this should be one page)
256     Add_Page_Range(IDT_LOCATION,TSS_LOCATION,PAGE_KERN);
257     // TSS (this should be one page)
258     Add_Page_Range(TSS_LOCATION,GDT_LOCATION, PAGE_KERN);
259     // GDT (this should be one page)
260     Add_Page_Range(GDT_LOCATION,TOP_OF_MEM, PAGE_KERN);
261
262     /* Initialize the kernel heap */
263     Init_Heap(KERNEL_HEAP, KERNEL_HEAP_SIZE);
264
265     PrintBoth("%uKB memory detected, %u pages in freelist, %d bytes in kernel heap\n",
266         bootInfo->memSizeKB, g_freePageCount, KERNEL_HEAP_SIZE);
267
268     PrintBoth("Memory Layout:\n");
269     PrintBoth("%x to %x - VM\n",START_OF_VM,START_OF_VM+VM_SIZE-1);
270     PrintBoth("%x to %x - INITIAL THREAD\n",KERNEL_THREAD_OBJECT,KERNEL_THREAD_OBJECT+KERNEL_THREAD_OBJECT_SIZE-1);
271     PrintBoth("%x to %x - KERNEL STACK\n",KERNEL_STACK,KERNEL_STACK+KERNEL_STACK_SIZE-1);
272     PrintBoth("%x to %x - KERNEL HEAP\n",KERNEL_HEAP,KERNEL_HEAP+KERNEL_HEAP_SIZE-1);
273     PrintBoth("%lx to %lx - PAGE LIST\n",pageListAddr,pageListEnd-1);
274     PrintBoth("%lx to %x - FREE\n",pageListEnd,FINAL_KERNEL_START-1);
275     PrintBoth("%x to %x - KERNEL CODE\n",FINAL_KERNEL_START,FINAL_KERNEL_END);
276     PrintBoth("%x to %x - VM_KERNEL\n", FINAL_VM_KERNEL_START, FINAL_VM_KERNEL_END);
277     PrintBoth("%x to %x - IDT\n",IDT_LOCATION,TSS_LOCATION-1);
278     PrintBoth("%x to %x - TSS\n",TSS_LOCATION,GDT_LOCATION-1);
279     PrintBoth("%x to %x - GDT\n",GDT_LOCATION,TOP_OF_MEM-1);
280
281
282 }
283
284 /*
285  * Initialize the .bss section of the kernel executable image.
286  */
287 void Init_BSS(void)
288 {
289     extern char BSS_START, BSS_END;
290
291     /* Fill .bss with zeroes */
292     memset(&BSS_START, '\0', &BSS_END - &BSS_START);
293     PrintBoth("BSS Inited, BSS_START=%x, BSS_END=%x\n",BSS_START,BSS_END);
294 }
295
296 /*
297  * Allocate a page of physical memory.
298  */
299 void* Alloc_Page(void)
300 {
301     struct Page* page;
302     void *result = 0;
303
304     bool iflag = Begin_Int_Atomic();
305
306     /* See if we have a free page */
307     if (!Is_Page_List_Empty(&s_freeList)) {
308         /* Remove the first page on the freelist. */
309         page = Get_Front_Of_Page_List(&s_freeList);
310         KASSERT((page->flags & PAGE_ALLOCATED) == 0);
311         Remove_From_Front_Of_Page_List(&s_freeList);
312
313         /* Mark page as having been allocated. */
314         page->flags |= PAGE_ALLOCATED;
315         g_freePageCount--;
316         result = (void*) Get_Page_Address(page);
317     }
318
319     End_Int_Atomic(iflag);
320
321     return result;
322 }
323
324 /*
325  * Free a page of physical memory.
326  */
327 void Free_Page(void* pageAddr)
328 {
329     ulong_t addr = (ulong_t) pageAddr;
330     struct Page* page;
331     bool iflag;
332
333     iflag = Begin_Int_Atomic();
334
335     KASSERT(Is_Page_Multiple(addr));
336
337     /* Get the Page object for this page */
338     page = Get_Page(addr);
339     KASSERT((page->flags & PAGE_ALLOCATED) != 0);
340
341     /* Clear the allocation bit */
342     page->flags &= ~(PAGE_ALLOCATED);
343
344     /* Put the page back on the freelist */
345     Add_To_Back_Of_Page_List(&s_freeList, page);
346     g_freePageCount++;
347
348     End_Int_Atomic(iflag);
349 }