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.


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