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.


6b3263d307a73ce26ff1e1eca489dd409dfc04e6
[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.8 $
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 /*
36  * Number of pages currently available on the freelist.
37  */
38 uint_t g_freePageCount = 0;
39
40
41
42 /* 
43  *  the disgusting way to get at the memory assigned to a VM
44  */
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;
49
50
51
52 /* ----------------------------------------------------------------------
53  * Private data and functions
54  * ---------------------------------------------------------------------- */
55
56 /*
57  * Defined in paging.c
58  */
59 extern int debugFaults;
60 #define Debug(args...) if (debugFaults) Print(args)
61
62 /*
63  * List of pages available for allocation.
64  */
65 static struct Page_List s_freeList;
66
67 /*
68  * Total number of physical pages.
69  */
70 int unsigned s_numPages;
71
72
73
74
75 /*
76  * Add a range of pages to the inventory of physical memory.
77  */
78 static void Add_Page_Range(ulong_t start, ulong_t end, int flags)
79 {
80     ulong_t addr;
81
82     PrintBoth("Start: %u, End: %u  (Type=0x%.4x)\n", (unsigned int)start, (unsigned int)end, flags);
83
84     KASSERT(Is_Page_Multiple(start));
85     KASSERT(Is_Page_Multiple(end));
86     KASSERT(start < end);
87
88     //Print("Adding %lu pages\n", (end - start) / PAGE_SIZE);
89
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);
93
94         page->flags = flags;
95
96         if (flags == PAGE_AVAIL) {
97             /* Add the page to the freelist */
98             Add_To_Back_Of_Page_List(&s_freeList, page);
99
100             /* Update free page count */
101             ++g_freePageCount;
102         } else {
103             Set_Next_In_Page_List(page, 0);
104             Set_Prev_In_Page_List(page, 0);
105         }
106
107     }
108     //   Print("%d pages now in freelist\n", g_freePageCount);
109
110 }
111
112 /* ----------------------------------------------------------------------
113  * Public functions
114  * ---------------------------------------------------------------------- */
115
116 /*
117  * The linker defines this symbol to indicate the end of
118  * the executable image.
119  */
120 extern char end;
121
122 /*
123  * Initialize memory management data structures.
124  * Enables the use of Alloc_Page() and Free_Page() functions.
125  */
126 void Init_Mem(struct Boot_Info* bootInfo)
127 {
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;
132     ulong_t pageListEnd;
133     ulong_t kernEnd;
134     ulong_t guestEnd;
135     ulong_t heapAddr;
136     ulong_t heapEnd;
137     ulong_t vmmMemEnd;
138
139
140     KASSERT(bootInfo->memSizeKB > 0);
141
142
143     /*
144      * Before we do anything, switch from setup.asm's temporary GDT
145      * to the kernel's permanent GDT.
146      */
147     Init_GDT();
148
149
150     PrintBoth("Total Memory Size: %u MBytes\n", bootInfo->memSizeKB/1024);
151     PrintBoth("Page List Size: %u bytes\n", numPageListBytes);
152
153   
154     /* Memory Layout:
155      * bios area (1 page reserved) 
156      * kernel_thread_obj (1 page)
157      * kernel_stack (1 page)
158      * available space
159      * start - end:       kernel
160      * available space
161      * ISA_HOLE_START - ISA_HOLE_END: hardware
162      * EXTENDED_MEMORY:
163      *        VM Guest (variable pages)
164      *        Heap (512 Pages)
165      *        Page List (variable pages)
166      *        Available Memory for VMM (4096 pages)
167      *        VM Memory (everything else)
168      */
169
170     kernEnd = Round_Up_To_Page((ulong_t)&end);
171     PrintBoth("Kernel End=%lx\n", kernEnd);
172
173
174     /* ************************************************************************************** */
175     /* If we have dynamic loading of the guest kernel, we should put the relocation code here */
176     /* ************************************************************************************** */
177
178     guestEnd = Round_Up_To_Page(ISA_HOLE_END + bootInfo->guest_size);
179     heapAddr = guestEnd;
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;
187     /* ** */
188     vmmMemEnd = Round_Up_To_Page(pageListEnd + VMM_AVAIL_MEM_SIZE);
189
190
191     /* 
192      *  the disgusting way to get at the memory assigned to a VM
193      */
194     vm_range_start = vmmMemEnd;
195     vm_range_end = endOfMem;
196     guest_kernel_start = ISA_HOLE_END;
197     guest_kernel_end = guestEnd;
198
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
210     // Until we get a more intelligent memory allocator
211     Add_Page_Range(vmmMemEnd, endOfMem, PAGE_AVAIL);                      // Memory allocated to the VM
212
213
214     /* Initialize the kernel heap */
215     Init_Heap(heapAddr, KERNEL_HEAP_SIZE);
216
217     PrintBoth("%uKB memory detected, %u pages in freelist, %d bytes in kernel heap\n",
218         bootInfo->memSizeKB, g_freePageCount, KERNEL_HEAP_SIZE);
219
220     PrintBoth("Memory Layout:\n");
221     PrintBoth("%x to %x - BIOS AREA\n", 0, PAGE_SIZE - 1);
222     PrintBoth("%x to %x - KERNEL_THREAD_OBJ\n", PAGE_SIZE, PAGE_SIZE * 2 - 1);
223     PrintBoth("%x to %x - KERNEL_STACK\n", PAGE_SIZE * 2, PAGE_SIZE * 3 - 1);
224     PrintBoth("%lx to %x - FREE\n", PAGE_SIZE * 3, KERNEL_START_ADDR - 1);
225     PrintBoth("%x to %x - KERNEL CODE\n", KERNEL_START_ADDR, kernEnd - 1);
226     PrintBoth("%lx to %x - FREE\n", kernEnd, ISA_HOLE_START - 1);
227     PrintBoth("%x to %x - ISA_HOLE\n", ISA_HOLE_START, ISA_HOLE_END - 1);
228     PrintBoth("%x to %x - VM_KERNEL\n", ISA_HOLE_END, guestEnd - 1);
229     PrintBoth("%x to %x - KERNEL HEAP\n", heapAddr, heapEnd - 1);
230     PrintBoth("%lx to %lx - PAGE LIST\n", pageListAddr, pageListEnd - 1);
231     PrintBoth("%lx to %x - FREE\n", pageListEnd, vmmMemEnd - 1);
232     PrintBoth("%lx to %x - GUEST_MEMORY (also free)\n", vmmMemEnd, endOfMem - 1);
233 }
234
235 /*
236  * Initialize the .bss section of the kernel executable image.
237  */
238 void Init_BSS(void)
239 {
240     extern char BSS_START, BSS_END;
241
242     /* Fill .bss with zeroes */
243     memset(&BSS_START, '\0', &BSS_END - &BSS_START);
244     // screen is not inited yet - PAD
245     // PrintBoth("BSS Inited, BSS_START=%x, BSS_END=%x\n",BSS_START,BSS_END);
246 }
247
248 /*
249  * Allocate a page of physical memory.
250  */
251 void* Alloc_Page(void)
252 {
253     struct Page* page;
254     void *result = 0;
255
256     bool iflag = Begin_Int_Atomic();
257
258     /* See if we have a free page */
259     if (!Is_Page_List_Empty(&s_freeList)) {
260         /* Remove the first page on the freelist. */
261         page = Get_Front_Of_Page_List(&s_freeList);
262         KASSERT((page->flags & PAGE_ALLOCATED) == 0);
263         Remove_From_Front_Of_Page_List(&s_freeList);
264
265         /* Mark page as having been allocated. */
266         page->flags |= PAGE_ALLOCATED;
267         g_freePageCount--;
268         result = (void*) Get_Page_Address(page);
269     }
270
271     End_Int_Atomic(iflag);
272
273     return result;
274 }
275
276 /*
277  * Free a page of physical memory.
278  */
279 void Free_Page(void* pageAddr)
280 {
281     ulong_t addr = (ulong_t) pageAddr;
282     struct Page* page;
283     bool iflag;
284
285     iflag = Begin_Int_Atomic();
286
287     KASSERT(Is_Page_Multiple(addr));
288
289     /* Get the Page object for this page */
290     page = Get_Page(addr);
291     KASSERT((page->flags & PAGE_ALLOCATED) != 0);
292
293     /* Clear the allocation bit */
294     page->flags &= ~(PAGE_ALLOCATED);
295
296     /* Put the page back on the freelist */
297     Add_To_Back_Of_Page_List(&s_freeList, page);
298     g_freePageCount++;
299
300     End_Int_Atomic(iflag);
301 }