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.


45df0b1b52f9a13ad0a499619c9e9bd8afcfbd2e
[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.13 $
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/serial.h>
23 #include <geekos/debug.h>
24
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 #ifdef RAMDISK_BOOT
36 ulong_t g_ramdiskImage;
37 ulong_t s_ramdiskSize;
38 #endif
39
40 /*
41  * Number of pages currently available on the freelist.
42  */
43 uint_t g_freePageCount = 0;
44
45
46
47 /* 
48  *  the disgusting way to get at the memory assigned to a VM
49  */
50 extern ulong_t vm_range_start;
51 extern ulong_t vm_range_end;
52 extern ulong_t guest_kernel_start;
53 extern ulong_t guest_kernel_end;
54
55
56
57 /* ----------------------------------------------------------------------
58  * Private data and functions
59  * ---------------------------------------------------------------------- */
60
61 /*
62  * Defined in paging.c
63  */
64 extern int debugFaults;
65 #define Debug(args...) if (debugFaults) Print(args)
66
67 /*
68  * List of pages available for allocation.
69  */
70 static struct Page_List s_freeList;
71
72 /*
73  * Total number of physical pages.
74  */
75 int unsigned s_numPages;
76
77
78
79
80 /*
81  * Add a range of pages to the inventory of physical memory.
82  */
83 static void Add_Page_Range(ulong_t start, ulong_t end, int flags)
84 {
85     ulong_t addr;
86
87     PrintBoth("Start: %u (0x%x), End: %u(0x%x)  (Type=0x%.4x)\n", (unsigned int)start, start, (unsigned int)end, end, flags);
88
89     KASSERT(Is_Page_Multiple(start));
90     KASSERT(Is_Page_Multiple(end));
91     KASSERT(start < end);
92
93     //Print("Adding %lu pages\n", (end - start) / PAGE_SIZE);
94
95     for (addr = start; addr < end; addr += PAGE_SIZE) {
96       //      Print("Adding Page at %u\n", (unsigned int)addr);
97         struct Page *page = Get_Page(addr);
98
99         page->flags = flags;
100
101         if (flags == PAGE_AVAIL) {
102             /* Add the page to the freelist */
103             Add_To_Back_Of_Page_List(&s_freeList, page);
104
105             /* Update free page count */
106             ++g_freePageCount;
107         } else {
108             Set_Next_In_Page_List(page, 0);
109             Set_Prev_In_Page_List(page, 0);
110         }
111
112     }
113     //   Print("%d pages now in freelist\n", g_freePageCount);
114
115 }
116
117 /* ----------------------------------------------------------------------
118  * Public functions
119  * ---------------------------------------------------------------------- */
120
121 /*
122  * The linker defines this symbol to indicate the end of
123  * the executable image.
124  */
125 extern char end;
126
127 /*
128  * Initialize memory management data structures.
129  * Enables the use of Alloc_Page() and Free_Page() functions.
130  */
131 void Init_Mem(struct Boot_Info* bootInfo)
132 {
133     ulong_t numPages = bootInfo->memSizeKB >> 2;
134     ulong_t endOfMem = numPages * PAGE_SIZE;
135     unsigned numPageListBytes = sizeof(struct Page) * numPages;
136     ulong_t pageListAddr;
137     ulong_t pageListEnd;
138     ulong_t kernEnd;
139     ulong_t heapAddr;
140     ulong_t heapEnd;
141     ulong_t vmmMemEnd;
142
143     /*Zheng 08/03/2008*/    
144 #ifdef RAMDISK_BOOT
145     g_ramdiskImage = bootInfo->ramdisk_image;
146     s_ramdiskSize = bootInfo->ramdisk_size;
147     ulong_t initrdAddr;
148     ulong_t initrdEnd;
149 #endif
150     
151
152     KASSERT(bootInfo->memSizeKB > 0);
153
154
155     /*
156      * Before we do anything, switch from setup.asm's temporary GDT
157      * to the kernel's permanent GDT.
158      */
159     Init_GDT();
160
161
162     PrintBoth("Total Memory Size: %u MBytes\n", bootInfo->memSizeKB/1024);
163     PrintBoth("Page List (at 0x%x) Size: %u bytes\n", &s_freeList, numPageListBytes);
164
165   
166     /* Memory Layout:
167      * bios area (1 page reserved) 
168      * kernel_thread_obj (1 page)
169      * kernel_stack (1 page)
170      * available space
171      * available space
172      * ISA_HOLE_START - ISA_HOLE_END: hardware
173      * EXTENDED_MEMORY:
174      *        start - end:       kernel
175      *        VM Guest (variable pages)
176      *        Heap (512 Pages)
177      *        Page List (variable pages)
178      *        Available Memory for VMM (4096 pages)
179      *        Ramdisk //Zheng 08/03/2008
180      *        VM Memory (everything else)
181      */
182
183     //kernEnd = Round_Up_To_Page((ulong_t)&end);
184     kernEnd = (ulong_t)&end;
185
186     PrintBoth("Kernel End=%lx\n", kernEnd);
187
188
189     /* ************************************************************************************** */
190     /* If we have dynamic loading of the guest kernel, we should put the relocation code here */
191     /* ************************************************************************************** */
192
193     kernEnd = Round_Up_To_Page(kernEnd);
194     heapAddr = kernEnd;
195     heapEnd = Round_Up_To_Page(heapAddr + KERNEL_HEAP_SIZE);
196     pageListAddr = heapEnd;
197     pageListEnd = Round_Up_To_Page(pageListAddr + numPageListBytes);
198     /* Global variables */
199     // These must be set before we can call Add_Page_Range..
200     g_pageList = (struct Page*) pageListAddr;
201     s_numPages = numPages;
202     /* ** */
203     vmmMemEnd = Round_Up_To_Page(pageListEnd + VMM_AVAIL_MEM_SIZE);
204
205 #ifdef RAMDISK_BOOT
206     /*
207      * Zheng 08/03/2008
208      * copy the ramdisk to this area 
209      */
210
211     initrdAddr = vmmMemEnd;
212     initrdEnd = Round_Up_To_Page(initrdAddr + s_ramdiskSize);
213     PrintBoth("mem.c(%d) Move ramdisk(%dB) from %x to %x", __LINE__, s_ramdiskSize, g_ramdiskImage, initrdAddr);
214     memcpy((ulong_t *)initrdAddr, (ulong_t *)g_ramdiskImage, s_ramdiskSize);
215     PrintBoth(" done\n");
216     PrintBoth("mem.c(%d) Set 0 to unused bytes in the last ramdisk page from %x to %x", __LINE__, initrdAddr+s_ramdiskSize, initrdEnd);
217     memset((ulong_t *)initrdAddr+s_ramdiskSize, 0, initrdEnd-(initrdAddr+s_ramdiskSize));
218     PrintBoth(" done\n");
219     /*
220      * Zheng 08/03/2008
221      */
222     vm_range_start = initrdEnd;
223     vm_range_end = endOfMem;
224 #else
225     
226     /* 
227      *  the disgusting way to get at the memory assigned to a VM
228      */
229     
230     vm_range_start = vmmMemEnd;
231     vm_range_end = endOfMem;
232     
233 #endif
234
235     Add_Page_Range(0, PAGE_SIZE, PAGE_UNUSED);                        // BIOS area
236     Add_Page_Range(PAGE_SIZE, PAGE_SIZE * 3, PAGE_ALLOCATED);         // Intial kernel thread obj + stack
237     Add_Page_Range(PAGE_SIZE * 3, ISA_HOLE_START, PAGE_AVAIL);     // Available space
238     Add_Page_Range(ISA_HOLE_START, ISA_HOLE_END, PAGE_HW);            // Hardware ROMs
239     Add_Page_Range(KERNEL_START_ADDR, kernEnd, PAGE_KERN);            // VMM Kernel
240     //    Add_Page_Range(guest_kernel_start, guestEnd, PAGE_VM);                  // Guest kernel location
241     Add_Page_Range(heapAddr, heapEnd, PAGE_HEAP);                     // Heap
242     Add_Page_Range(pageListAddr, pageListEnd, PAGE_KERN);             // Page List 
243     Add_Page_Range(pageListEnd, vmmMemEnd, PAGE_AVAIL);               // Available VMM memory
244
245 #ifdef RAMDISK_BOOT
246     /*
247      * Zheng 08/03/2008
248      */
249     Add_Page_Range(vmmMemEnd, initrdEnd, PAGE_ALLOCATED);              //Ramdisk memory area      
250     //    Add_Page_Range(vmmMemEnd, endOfMem, PAGE_VM);                // Memory allocated to the VM
251     // Until we get a more intelligent memory allocator
252     Add_Page_Range(initrdEnd, endOfMem, PAGE_AVAIL);                   // Memory allocated to the VM
253 #else
254     Add_Page_Range(vmmMemEnd, endOfMem, PAGE_AVAIL);                   // Memory allocated to the VM
255 #endif
256
257     /* Initialize the kernel heap */
258     Init_Heap(heapAddr, 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 - BIOS AREA\n", 0, PAGE_SIZE - 1);
265     PrintBoth("%x to %x - KERNEL_THREAD_OBJ\n", PAGE_SIZE, PAGE_SIZE * 2 - 1);
266     PrintBoth("%x to %x - KERNEL_STACK\n", PAGE_SIZE * 2, PAGE_SIZE * 3 - 1);
267     PrintBoth("%lx to %x - FREE\n", PAGE_SIZE * 3, ISA_HOLE_START - 1);
268     PrintBoth("%x to %x - ISA_HOLE\n", ISA_HOLE_START, ISA_HOLE_END - 1);
269     PrintBoth("%x to %x - KERNEL CODE + VM_KERNEL\n", KERNEL_START_ADDR, kernEnd - 1);
270     //    PrintBoth("%x to %x - VM_KERNEL\n", kernEnd, guestEnd - 1);
271     PrintBoth("%x to %x - KERNEL HEAP\n", heapAddr, heapEnd - 1);
272     PrintBoth("%lx to %lx - PAGE LIST\n", pageListAddr, pageListEnd - 1);
273     PrintBoth("%lx to %x - FREE\n", pageListEnd, vmmMemEnd - 1);
274
275 #ifdef RAMDISK_BOOT
276     /*
277      * Zheng 08/03/2008
278      */
279     PrintBoth("%lx to %x - RAMDISK\n", vmmMemEnd, initrdEnd - 1);
280
281     PrintBoth("%lx to %x - GUEST_MEMORY (also free)\n", initrdEnd, endOfMem - 1);
282 #else
283     PrintBoth("%lx to %x - GUEST_MEMORY (also free)\n", vmmMemEnd, endOfMem - 1);
284 #endif
285 }
286
287 /*
288  * Initialize the .bss section of the kernel executable image.
289  */
290 void Init_BSS(void)
291 {
292     extern char BSS_START, BSS_END;
293
294     /* Fill .bss with zeroes */
295     memset(&BSS_START, '\0', &BSS_END - &BSS_START);
296     // screen is not inited yet - PAD
297     // PrintBoth("BSS Inited, BSS_START=%x, BSS_END=%x\n",BSS_START,BSS_END);
298 }
299
300 /*
301  * Allocate a page of physical memory.
302  */
303 void* Alloc_Page(void)
304 {
305     struct Page* page;
306     void *result = 0;
307
308     bool iflag = Begin_Int_Atomic();
309
310     /* See if we have a free page */
311     if (!Is_Page_List_Empty(&s_freeList)) {
312         /* Remove the first page on the freelist. */
313         page = Get_Front_Of_Page_List(&s_freeList);
314         KASSERT((page->flags & PAGE_ALLOCATED) == 0);
315         Remove_From_Front_Of_Page_List(&s_freeList);
316
317         /* Mark page as having been allocated. */
318         page->flags |= PAGE_ALLOCATED;
319         g_freePageCount--;
320         result = (void*) Get_Page_Address(page);
321     }
322
323     End_Int_Atomic(iflag);
324
325     return result;
326 }
327
328 /*
329  * Free a page of physical memory.
330  */
331 void Free_Page(void* pageAddr)
332 {
333     ulong_t addr = (ulong_t) pageAddr;
334     struct Page* page;
335     bool iflag;
336
337     iflag = Begin_Int_Atomic();
338
339     KASSERT(Is_Page_Multiple(addr));
340
341     /* Get the Page object for this page */
342     page = Get_Page(addr);
343     KASSERT((page->flags & PAGE_ALLOCATED) != 0);
344
345     /* Clear the allocation bit */
346     page->flags &= ~(PAGE_ALLOCATED);
347
348     /* Put the page back on the freelist */
349     Add_To_Back_Of_Page_List(&s_freeList, page);
350     g_freePageCount++;
351
352     End_Int_Atomic(iflag);
353 }