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.


(no commit message)
[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.1.1.1 $
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     //Print("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     KASSERT(bootInfo->memSizeKB > 0);
120
121     if (bootInfo->memSizeKB != TOP_OF_MEM/1024) { 
122       PrintBoth("Kernel compiled for %d KB machine, but machine claims %d KB\n",TOP_OF_MEM/1024,bootInfo->memSizeKB);
123       if (bootInfo->memSizeKB < TOP_OF_MEM/1024) { 
124         PrintBoth("Kernel compiled for more memory than machine has.  Panicking\n");
125         KASSERT(0);
126       }
127     }
128
129     if (0) {
130       // if there is not enough memory between START_OF_VM+VM_SIZE and TOP_OF_MEM
131       // to store the kernel and kernel structures, we need to panick
132       PrintBoth("Kernel is not compiled with sufficient memory above the VM to support the memory\n");
133       KASSERT(0);
134     }
135
136
137     bootInfo->memSizeKB = TOP_OF_MEM / 1024;
138
139     /*
140      * Before we do anything, switch from setup.asm's temporary GDT
141      * to the kernel's permanent GDT.
142      */
143     Init_GDT();
144
145     /*
146      * We'll put the list of Page objects right after the end
147      * of the kernel, and mark it as "kernel".  This will bootstrap
148      * us sufficiently that we can start allocating pages and
149      * keeping track of them.
150      */
151
152     // JRL: This is stupid... 
153     // with large mem sizes the page list overruns into the ISA 
154     // hole. By blind luck this causes an unrelated assertion failure, otherwise
155     // I might never have caught it...
156     // We fix it by moving the page list after the kernel heap...
157     // For now we'll make our own stupid assumption that the mem size
158     // is large enough to accomodate the list in high mem.
159
160     PrintBoth("Total Memory Size: %u MBytes\n", bootInfo->memSizeKB/1024);
161     PrintBoth("VM Start: %x\n",START_OF_VM);
162     PrintBoth("VM End: %x\n",START_OF_VM+VM_SIZE-1);
163     
164
165     PrintBoth("Page struct size: %u bytes\n", sizeof(struct Page));
166     PrintBoth("Page List Size: %u bytes\n", numPageListBytes);
167
168   
169     //pageListAddr = Round_Up_To_Page((ulong_t) &end);
170     //pageListAddr = Round_Up_To_Page(HIGHMEM_START + KERNEL_HEAP_SIZE);
171
172     // Note that this is now moved to be just above the kernel heap
173     // see defs.h for layout
174     pageListAddr=Round_Up_To_Page(KERNEL_PAGELIST);
175       
176     pageListEnd = Round_Up_To_Page(pageListAddr + numPageListBytes);
177
178     g_pageList = (struct Page*) pageListAddr;
179     //    kernEnd = Round_Up_To_Page(pageListAddr + numPageListBytes);
180     //
181     // PAD - Note: I am changing this so that everything through the end of 
182     // the VM boot package (bioses/vmxassist) is off limits
183     //kernEnd = Round_Up_To_Page((ulong_t) &end);
184     kernEnd = Round_Up_To_Page(VM_BOOT_PACKAGE_END);
185     s_numPages = numPages;
186
187     PrintBoth("Pagelist addr: %p\n", g_pageList);
188     PrintBoth("index: %p\n", &g_pageList[3]);
189     PrintBoth("direct offset: %p\n", g_pageList + (sizeof(struct Page) * 2));
190     PrintBoth("Kernel Size=%lx\n", (kernEnd - KERNEL_START_ADDR));
191     PrintBoth("Kernel Start=%x\n", KERNEL_START_ADDR);
192     PrintBoth("Kernel End=%lx\n", kernEnd);
193     PrintBoth("VM Boot Package Start=%x\n", VM_BOOT_PACKAGE_START);
194     PrintBoth("VM Boot Package End=%x\n", VM_BOOT_PACKAGE_END);
195
196     /*
197      * The initial kernel thread and its stack are placed
198      * just beyond the ISA hole.
199      */
200     // This is no longer true
201     // KASSERT(ISA_HOLE_END == KERN_THREAD_OBJ);
202     // instead, 
203     //KASSERT(KERN_THREAD_OBJ==(START_OF_VM+VM_SIZE));
204     //KASSERT(KERN_STACK == KERN_THREAD_OBJ + PAGE_SIZE);
205
206     /*
207      * Memory looks like this:
208      * 0 - start: available (might want to preserve BIOS data area)
209      * start - end: kernel
210      * end - ISA_HOLE_START: available
211      * ISA_HOLE_START - ISA_HOLE_END: used by hardware (and ROM BIOS?)
212      * ISA_HOLE_END - HIGHMEM_START: used by initial kernel thread
213      * HIGHMEM_START - end of memory: available
214      *    (the kernel heap is located at HIGHMEM_START; any unused memory
215      *    beyond that is added to the freelist)
216      */
217
218     // The VM region... 0 .. VM size is out of bounds
219     KASSERT(START_OF_VM==0);
220     Add_Page_Range(START_OF_VM, START_OF_VM+VM_SIZE, PAGE_VM);
221     // The kernel is still in low memory at this point, in the VM region
222     // Thus we will mark it as kernel use
223     // Add_Page_Range(KERNEL_START_ADDR, kernEnd, PAGE_KERN);
224     
225     
226     //Add_Page_Range(kernEnd, ISA_HOLE_START, PAGE_AVAIL);
227     // ISA hole remains closed (no actual memory)
228     // Add_Page_Range(ISA_HOLE_START, ISA_HOLE_END, PAGE_HW);
229     
230     //Add_Page_Range(ISA_HOLE_END, HIGHMEM_START, PAGE_ALLOCATED);
231     // Add_Page_Range(HIGHMEM_START, HIGHMEM_START + KERNEL_HEAP_SIZE, PAGE_HEAP);
232     //Add_Page_Range(HIGHMEM_START + KERNEL_HEAP_SIZE, endOfMem, PAGE_AVAIL);
233     /* JRL: move page list after kernel heap */
234     
235     //Now, above the VM region...
236
237     // Kernel thread object
238     Add_Page_Range(KERNEL_THREAD_OBJECT,KERNEL_THREAD_OBJECT+KERNEL_THREAD_OBJECT_SIZE,PAGE_ALLOCATED);
239     // Kernel stack
240     Add_Page_Range(KERNEL_STACK,KERNEL_STACK+KERNEL_STACK_SIZE,PAGE_ALLOCATED);
241     // Kernel heap
242     Add_Page_Range(KERNEL_HEAP,KERNEL_HEAP+KERNEL_HEAP_SIZE,PAGE_HEAP);
243     // Kernel page list
244     Add_Page_Range(pageListAddr, pageListEnd, PAGE_KERN);
245     // Free space
246     Add_Page_Range(pageListEnd,Round_Down_To_Page(FINAL_KERNEL_START), PAGE_AVAIL);
247     // The kernel 
248     Add_Page_Range(Round_Down_To_Page(FINAL_KERNEL_START),Round_Up_To_Page(FINAL_VMBOOTEND+1),PAGE_KERN);
249     // The vmbootpackage 
250     // IDT (this should be one page)
251     Add_Page_Range(IDT_LOCATION,TSS_LOCATION,PAGE_KERN);
252     // TSS (this should be one page)
253     Add_Page_Range(TSS_LOCATION,GDT_LOCATION, PAGE_KERN);
254     // GDT (this should be one page)
255     Add_Page_Range(GDT_LOCATION,TOP_OF_MEM, PAGE_KERN);
256
257     /* Initialize the kernel heap */
258     Init_Heap(KERNEL_HEAP, KERNEL_HEAP_SIZE);
259
260     PrintBoth("%uKB memory detected, %u pages in freelist, %d bytes in kernel heap\n",
261         bootInfo->memSizeKB, g_freePageCount, KERNEL_HEAP_SIZE);
262
263     PrintBoth("Memory Layout:\n");
264     PrintBoth("%x to %x - VM\n",START_OF_VM,START_OF_VM+VM_SIZE-1);
265     PrintBoth("%x to %x - INITIAL THREAD\n",KERNEL_THREAD_OBJECT,KERNEL_THREAD_OBJECT+KERNEL_THREAD_OBJECT_SIZE-1);
266     PrintBoth("%x to %x - KERNEL STACK\n",KERNEL_STACK,KERNEL_STACK+KERNEL_STACK_SIZE-1);
267     PrintBoth("%x to %x - KERNEL HEAP\n",KERNEL_HEAP,KERNEL_HEAP+KERNEL_HEAP_SIZE-1);
268     PrintBoth("%lx to %lx - PAGE LIST\n",pageListAddr,pageListEnd-1);
269     PrintBoth("%lx to %x - FREE\n",pageListEnd,FINAL_KERNEL_START-1);
270     PrintBoth("%x to %x - KERNEL CODE\n",FINAL_KERNEL_START,FINAL_KERNEL_END);
271     PrintBoth("%x to %x - BIOS\n",FINAL_BIOS_START,FINAL_BIOS_END);
272     PrintBoth("%x to %x - VGABIOS\n",FINAL_VGA_BIOS_START,FINAL_VGA_BIOS_END);
273     PrintBoth("%x to %x - VMXASSIST\n",FINAL_VMXASSIST_START,FINAL_VMXASSIST_END);
274     PrintBoth("%x to %x - BIOS (2nd copy)\n",FINAL_BIOS2_START,FINAL_BIOS2_END);
275     PrintBoth("%x to %x - IDT\n",IDT_LOCATION,TSS_LOCATION-1);
276     PrintBoth("%x to %x - TSS\n",TSS_LOCATION,GDT_LOCATION-1);
277     PrintBoth("%x to %x - GDT\n",GDT_LOCATION,TOP_OF_MEM-1);
278
279 }
280
281 /*
282  * Initialize the .bss section of the kernel executable image.
283  */
284 void Init_BSS(void)
285 {
286     extern char BSS_START, BSS_END;
287
288     /* Fill .bss with zeroes */
289     memset(&BSS_START, '\0', &BSS_END - &BSS_START);
290     PrintBoth("BSS Inited, BSS_START=%x, BSS_END=%x\n",BSS_START,BSS_END);
291 }
292
293 /*
294  * Allocate a page of physical memory.
295  */
296 void* Alloc_Page(void)
297 {
298     struct Page* page;
299     void *result = 0;
300
301     bool iflag = Begin_Int_Atomic();
302
303     /* See if we have a free page */
304     if (!Is_Page_List_Empty(&s_freeList)) {
305         /* Remove the first page on the freelist. */
306         page = Get_Front_Of_Page_List(&s_freeList);
307         KASSERT((page->flags & PAGE_ALLOCATED) == 0);
308         Remove_From_Front_Of_Page_List(&s_freeList);
309
310         /* Mark page as having been allocated. */
311         page->flags |= PAGE_ALLOCATED;
312         g_freePageCount--;
313         result = (void*) Get_Page_Address(page);
314     }
315
316     End_Int_Atomic(iflag);
317
318     return result;
319 }
320
321 /*
322  * Free a page of physical memory.
323  */
324 void Free_Page(void* pageAddr)
325 {
326     ulong_t addr = (ulong_t) pageAddr;
327     struct Page* page;
328     bool iflag;
329
330     iflag = Begin_Int_Atomic();
331
332     KASSERT(Is_Page_Multiple(addr));
333
334     /* Get the Page object for this page */
335     page = Get_Page(addr);
336     KASSERT((page->flags & PAGE_ALLOCATED) != 0);
337
338     /* Clear the allocation bit */
339     page->flags &= ~(PAGE_ALLOCATED);
340
341     /* Put the page back on the freelist */
342     Add_To_Back_Of_Page_List(&s_freeList, page);
343     g_freePageCount++;
344
345     End_Int_Atomic(iflag);
346 }