direct-io.hg

view extras/mini-os/mm.c @ 12477:7f7aeaa0cba6

[HVMLOADEr] Reserve MMIO 0xa0000 to 0xc0000 in ACPI dsdt.

Avoids possible vga driver loading problem in HVM Windows guest.
Also fixes a Makefile bug in hvmloader directory.

Signed-off-by: Qing He <qing.he@intel.com>
author kfraser@localhost.localdomain
date Fri Nov 17 10:02:54 2006 +0000 (2006-11-17)
parents e343f1850be0
children a3c6479c87ef
line source
1 /*
2 ****************************************************************************
3 * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
4 * (C) 2005 - Grzegorz Milos - Intel Research Cambridge
5 ****************************************************************************
6 *
7 * File: mm.c
8 * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
9 * Changes: Grzegorz Milos
10 *
11 * Date: Aug 2003, chages Aug 2005
12 *
13 * Environment: Xen Minimal OS
14 * Description: memory management related functions
15 * contains buddy page allocator from Xen.
16 *
17 ****************************************************************************
18 * Permission is hereby granted, free of charge, to any person obtaining a copy
19 * of this software and associated documentation files (the "Software"), to
20 * deal in the Software without restriction, including without limitation the
21 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
22 * sell copies of the Software, and to permit persons to whom the Software is
23 * furnished to do so, subject to the following conditions:
24 *
25 * The above copyright notice and this permission notice shall be included in
26 * all copies or substantial portions of the Software.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
34 * DEALINGS IN THE SOFTWARE.
35 */
37 #include <os.h>
38 #include <hypervisor.h>
39 #include <mm.h>
40 #include <types.h>
41 #include <lib.h>
42 #include <xmalloc.h>
44 #ifdef MM_DEBUG
45 #define DEBUG(_f, _a...) \
46 printk("MINI_OS(file=mm.c, line=%d) " _f "\n", __LINE__, ## _a)
47 #else
48 #define DEBUG(_f, _a...) ((void)0)
49 #endif
51 unsigned long *phys_to_machine_mapping;
52 extern char *stack;
53 extern void page_walk(unsigned long virt_addr);
55 /*********************
56 * ALLOCATION BITMAP
57 * One bit per page of memory. Bit set => page is allocated.
58 */
60 static unsigned long *alloc_bitmap;
61 #define PAGES_PER_MAPWORD (sizeof(unsigned long) * 8)
63 #define allocated_in_map(_pn) \
64 (alloc_bitmap[(_pn)/PAGES_PER_MAPWORD] & (1<<((_pn)&(PAGES_PER_MAPWORD-1))))
66 /*
67 * Hint regarding bitwise arithmetic in map_{alloc,free}:
68 * -(1<<n) sets all bits >= n.
69 * (1<<n)-1 sets all bits < n.
70 * Variable names in map_{alloc,free}:
71 * *_idx == Index into `alloc_bitmap' array.
72 * *_off == Bit offset within an element of the `alloc_bitmap' array.
73 */
75 static void map_alloc(unsigned long first_page, unsigned long nr_pages)
76 {
77 unsigned long start_off, end_off, curr_idx, end_idx;
79 curr_idx = first_page / PAGES_PER_MAPWORD;
80 start_off = first_page & (PAGES_PER_MAPWORD-1);
81 end_idx = (first_page + nr_pages) / PAGES_PER_MAPWORD;
82 end_off = (first_page + nr_pages) & (PAGES_PER_MAPWORD-1);
84 if ( curr_idx == end_idx )
85 {
86 alloc_bitmap[curr_idx] |= ((1<<end_off)-1) & -(1<<start_off);
87 }
88 else
89 {
90 alloc_bitmap[curr_idx] |= -(1<<start_off);
91 while ( ++curr_idx < end_idx ) alloc_bitmap[curr_idx] = ~0L;
92 alloc_bitmap[curr_idx] |= (1<<end_off)-1;
93 }
94 }
97 static void map_free(unsigned long first_page, unsigned long nr_pages)
98 {
99 unsigned long start_off, end_off, curr_idx, end_idx;
101 curr_idx = first_page / PAGES_PER_MAPWORD;
102 start_off = first_page & (PAGES_PER_MAPWORD-1);
103 end_idx = (first_page + nr_pages) / PAGES_PER_MAPWORD;
104 end_off = (first_page + nr_pages) & (PAGES_PER_MAPWORD-1);
106 if ( curr_idx == end_idx )
107 {
108 alloc_bitmap[curr_idx] &= -(1<<end_off) | ((1<<start_off)-1);
109 }
110 else
111 {
112 alloc_bitmap[curr_idx] &= (1<<start_off)-1;
113 while ( ++curr_idx != end_idx ) alloc_bitmap[curr_idx] = 0;
114 alloc_bitmap[curr_idx] &= -(1<<end_off);
115 }
116 }
120 /*************************
121 * BINARY BUDDY ALLOCATOR
122 */
124 typedef struct chunk_head_st chunk_head_t;
125 typedef struct chunk_tail_st chunk_tail_t;
127 struct chunk_head_st {
128 chunk_head_t *next;
129 chunk_head_t **pprev;
130 int level;
131 };
133 struct chunk_tail_st {
134 int level;
135 };
137 /* Linked lists of free chunks of different powers-of-two in size. */
138 #define FREELIST_SIZE ((sizeof(void*)<<3)-PAGE_SHIFT)
139 static chunk_head_t *free_head[FREELIST_SIZE];
140 static chunk_head_t free_tail[FREELIST_SIZE];
141 #define FREELIST_EMPTY(_l) ((_l)->next == NULL)
143 #define round_pgdown(_p) ((_p)&PAGE_MASK)
144 #define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
146 #ifdef MM_DEBUG
147 /*
148 * Prints allocation[0/1] for @nr_pages, starting at @start
149 * address (virtual).
150 */
151 USED static void print_allocation(void *start, int nr_pages)
152 {
153 unsigned long pfn_start = virt_to_pfn(start);
154 int count;
155 for(count = 0; count < nr_pages; count++)
156 if(allocated_in_map(pfn_start + count)) printk("1");
157 else printk("0");
159 printk("\n");
160 }
162 /*
163 * Prints chunks (making them with letters) for @nr_pages starting
164 * at @start (virtual).
165 */
166 USED static void print_chunks(void *start, int nr_pages)
167 {
168 char chunks[1001], current='A';
169 int order, count;
170 chunk_head_t *head;
171 unsigned long pfn_start = virt_to_pfn(start);
173 memset(chunks, (int)'_', 1000);
174 if(nr_pages > 1000)
175 {
176 DEBUG("Can only pring 1000 pages. Increase buffer size.");
177 }
179 for(order=0; order < FREELIST_SIZE; order++)
180 {
181 head = free_head[order];
182 while(!FREELIST_EMPTY(head))
183 {
184 for(count = 0; count < 1<< head->level; count++)
185 {
186 if(count + virt_to_pfn(head) - pfn_start < 1000)
187 chunks[count + virt_to_pfn(head) - pfn_start] = current;
188 }
189 head = head->next;
190 current++;
191 }
192 }
193 chunks[nr_pages] = '\0';
194 printk("%s\n", chunks);
195 }
196 #endif
199 /*
200 * Initialise allocator, placing addresses [@min,@max] in free pool.
201 * @min and @max are PHYSICAL addresses.
202 */
203 static void init_page_allocator(unsigned long min, unsigned long max)
204 {
205 int i;
206 unsigned long range, bitmap_size;
207 chunk_head_t *ch;
208 chunk_tail_t *ct;
209 for ( i = 0; i < FREELIST_SIZE; i++ )
210 {
211 free_head[i] = &free_tail[i];
212 free_tail[i].pprev = &free_head[i];
213 free_tail[i].next = NULL;
214 }
216 min = round_pgup (min);
217 max = round_pgdown(max);
219 /* Allocate space for the allocation bitmap. */
220 bitmap_size = (max+1) >> (PAGE_SHIFT+3);
221 bitmap_size = round_pgup(bitmap_size);
222 alloc_bitmap = (unsigned long *)to_virt(min);
223 min += bitmap_size;
224 range = max - min;
226 /* All allocated by default. */
227 memset(alloc_bitmap, ~0, bitmap_size);
228 /* Free up the memory we've been given to play with. */
229 map_free(min>>PAGE_SHIFT, range>>PAGE_SHIFT);
231 /* The buddy lists are addressed in high memory. */
232 min += VIRT_START;
233 max += VIRT_START;
235 while ( range != 0 )
236 {
237 /*
238 * Next chunk is limited by alignment of min, but also
239 * must not be bigger than remaining range.
240 */
241 for ( i = PAGE_SHIFT; (1<<(i+1)) <= range; i++ )
242 if ( min & (1<<i) ) break;
245 ch = (chunk_head_t *)min;
246 min += (1<<i);
247 range -= (1<<i);
248 ct = (chunk_tail_t *)min-1;
249 i -= PAGE_SHIFT;
250 ch->level = i;
251 ch->next = free_head[i];
252 ch->pprev = &free_head[i];
253 ch->next->pprev = &ch->next;
254 free_head[i] = ch;
255 ct->level = i;
256 }
257 }
260 /* Allocate 2^@order contiguous pages. Returns a VIRTUAL address. */
261 unsigned long alloc_pages(int order)
262 {
263 int i;
264 chunk_head_t *alloc_ch, *spare_ch;
265 chunk_tail_t *spare_ct;
268 /* Find smallest order which can satisfy the request. */
269 for ( i = order; i < FREELIST_SIZE; i++ ) {
270 if ( !FREELIST_EMPTY(free_head[i]) )
271 break;
272 }
274 if ( i == FREELIST_SIZE ) goto no_memory;
276 /* Unlink a chunk. */
277 alloc_ch = free_head[i];
278 free_head[i] = alloc_ch->next;
279 alloc_ch->next->pprev = alloc_ch->pprev;
281 /* We may have to break the chunk a number of times. */
282 while ( i != order )
283 {
284 /* Split into two equal parts. */
285 i--;
286 spare_ch = (chunk_head_t *)((char *)alloc_ch + (1<<(i+PAGE_SHIFT)));
287 spare_ct = (chunk_tail_t *)((char *)spare_ch + (1<<(i+PAGE_SHIFT)))-1;
289 /* Create new header for spare chunk. */
290 spare_ch->level = i;
291 spare_ch->next = free_head[i];
292 spare_ch->pprev = &free_head[i];
293 spare_ct->level = i;
295 /* Link in the spare chunk. */
296 spare_ch->next->pprev = &spare_ch->next;
297 free_head[i] = spare_ch;
298 }
300 map_alloc(to_phys(alloc_ch)>>PAGE_SHIFT, 1<<order);
302 return((unsigned long)alloc_ch);
304 no_memory:
306 printk("Cannot handle page request order %d!\n", order);
308 return 0;
309 }
311 void free_pages(void *pointer, int order)
312 {
313 chunk_head_t *freed_ch, *to_merge_ch;
314 chunk_tail_t *freed_ct;
315 unsigned long mask;
317 /* First free the chunk */
318 map_free(virt_to_pfn(pointer), 1 << order);
320 /* Create free chunk */
321 freed_ch = (chunk_head_t *)pointer;
322 freed_ct = (chunk_tail_t *)((char *)pointer + (1<<(order + PAGE_SHIFT)))-1;
324 /* Now, possibly we can conseal chunks together */
325 while(order < FREELIST_SIZE)
326 {
327 mask = 1 << (order + PAGE_SHIFT);
328 if((unsigned long)freed_ch & mask)
329 {
330 to_merge_ch = (chunk_head_t *)((char *)freed_ch - mask);
331 if(allocated_in_map(virt_to_pfn(to_merge_ch)) ||
332 to_merge_ch->level != order)
333 break;
335 /* Merge with predecessor */
336 freed_ch = to_merge_ch;
337 }
338 else
339 {
340 to_merge_ch = (chunk_head_t *)((char *)freed_ch + mask);
341 if(allocated_in_map(virt_to_pfn(to_merge_ch)) ||
342 to_merge_ch->level != order)
343 break;
345 /* Merge with successor */
346 freed_ct = (chunk_tail_t *)((char *)to_merge_ch + mask) - 1;
347 }
349 /* We are commited to merging, unlink the chunk */
350 *(to_merge_ch->pprev) = to_merge_ch->next;
351 to_merge_ch->next->pprev = to_merge_ch->pprev;
353 order++;
354 }
356 /* Link the new chunk */
357 freed_ch->level = order;
358 freed_ch->next = free_head[order];
359 freed_ch->pprev = &free_head[order];
360 freed_ct->level = order;
362 freed_ch->next->pprev = &freed_ch->next;
363 free_head[order] = freed_ch;
365 }
368 void new_pt_frame(unsigned long *pt_pfn, unsigned long prev_l_mfn,
369 unsigned long offset, unsigned long level)
370 {
371 pgentry_t *tab = (pgentry_t *)start_info.pt_base;
372 unsigned long pt_page = (unsigned long)pfn_to_virt(*pt_pfn);
373 unsigned long prot_e, prot_t, pincmd;
374 mmu_update_t mmu_updates[1];
375 struct mmuext_op pin_request;
377 DEBUG("Allocating new L%d pt frame for pt_pfn=%lx, "
378 "prev_l_mfn=%lx, offset=%lx",
379 level, *pt_pfn, prev_l_mfn, offset);
381 /* We need to clear the page, otherwise we might fail to map it
382 as a page table page */
383 memset((unsigned long*)pfn_to_virt(*pt_pfn), 0, PAGE_SIZE);
385 switch ( level )
386 {
387 case L1_FRAME:
388 prot_e = L1_PROT;
389 prot_t = L2_PROT;
390 pincmd = MMUEXT_PIN_L1_TABLE;
391 break;
392 #if defined(__x86_64__) || defined(CONFIG_X86_PAE)
393 case L2_FRAME:
394 prot_e = L2_PROT;
395 prot_t = L3_PROT;
396 pincmd = MMUEXT_PIN_L2_TABLE;
397 break;
398 #endif
399 #if defined(__x86_64__)
400 case L3_FRAME:
401 prot_e = L3_PROT;
402 prot_t = L4_PROT;
403 pincmd = MMUEXT_PIN_L3_TABLE;
404 break;
405 #endif
406 default:
407 printk("new_pt_frame() called with invalid level number %d\n", level);
408 do_exit();
409 break;
410 }
411 /* Update the entry */
412 #if defined(__x86_64__)
413 tab = pte_to_virt(tab[l4_table_offset(pt_page)]);
414 tab = pte_to_virt(tab[l3_table_offset(pt_page)]);
415 #endif
416 #if defined(CONFIG_X86_PAE)
417 tab = pte_to_virt(tab[l3_table_offset(pt_page)]);
418 #endif
420 mmu_updates[0].ptr = ((pgentry_t)tab[l2_table_offset(pt_page)] & PAGE_MASK) +
421 sizeof(pgentry_t) * l1_table_offset(pt_page);
422 mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT |
423 (prot_e & ~_PAGE_RW);
424 if(HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF) < 0)
425 {
426 printk("PTE for new page table page could not be updated\n");
427 do_exit();
428 }
430 /* Pin the page to provide correct protection */
431 pin_request.cmd = pincmd;
432 pin_request.arg1.mfn = pfn_to_mfn(*pt_pfn);
433 if(HYPERVISOR_mmuext_op(&pin_request, 1, NULL, DOMID_SELF) < 0)
434 {
435 printk("ERROR: pinning failed\n");
436 do_exit();
437 }
439 /* Now fill the new page table page with entries.
440 Update the page directory as well. */
441 mmu_updates[0].ptr = ((pgentry_t)prev_l_mfn << PAGE_SHIFT) + sizeof(pgentry_t) * offset;
442 mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT | prot_t;
443 if(HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF) < 0)
444 {
445 printk("ERROR: mmu_update failed\n");
446 do_exit();
447 }
448 *pt_pfn += 1;
449 }
451 /* Checks if a pagetable frame is needed (if weren't allocated by Xen) */
452 static int need_pt_frame(unsigned long virt_address, int level)
453 {
454 unsigned long hyp_virt_start = HYPERVISOR_VIRT_START;
455 #if defined(__x86_64__)
456 unsigned long hyp_virt_end = HYPERVISOR_VIRT_END;
457 #else
458 unsigned long hyp_virt_end = 0xffffffff;
459 #endif
461 /* In general frames will _not_ be needed if they were already
462 allocated to map the hypervisor into our VA space */
463 #if defined(__x86_64__)
464 if(level == L3_FRAME)
465 {
466 if(l4_table_offset(virt_address) >=
467 l4_table_offset(hyp_virt_start) &&
468 l4_table_offset(virt_address) <=
469 l4_table_offset(hyp_virt_end))
470 return 0;
471 return 1;
472 } else
473 #endif
475 #if defined(__x86_64__) || defined(CONFIG_X86_PAE)
476 if(level == L2_FRAME)
477 {
478 #if defined(__x86_64__)
479 if(l4_table_offset(virt_address) >=
480 l4_table_offset(hyp_virt_start) &&
481 l4_table_offset(virt_address) <=
482 l4_table_offset(hyp_virt_end))
483 #endif
484 if(l3_table_offset(virt_address) >=
485 l3_table_offset(hyp_virt_start) &&
486 l3_table_offset(virt_address) <=
487 l3_table_offset(hyp_virt_end))
488 return 0;
490 return 1;
491 } else
492 #endif /* defined(__x86_64__) || defined(CONFIG_X86_PAE) */
494 /* Always need l1 frames */
495 if(level == L1_FRAME)
496 return 1;
498 printk("ERROR: Unknown frame level %d, hypervisor %llx,%llx\n",
499 level, hyp_virt_start, hyp_virt_end);
500 return -1;
501 }
503 void build_pagetable(unsigned long *start_pfn, unsigned long *max_pfn)
504 {
505 unsigned long start_address, end_address;
506 unsigned long pfn_to_map, pt_pfn = *start_pfn;
507 static mmu_update_t mmu_updates[L1_PAGETABLE_ENTRIES + 1];
508 pgentry_t *tab = (pgentry_t *)start_info.pt_base, page;
509 unsigned long mfn = pfn_to_mfn(virt_to_pfn(start_info.pt_base));
510 unsigned long offset;
511 int count = 0;
513 pfn_to_map = (start_info.nr_pt_frames - NOT_L1_FRAMES) * L1_PAGETABLE_ENTRIES;
515 if (*max_pfn >= virt_to_pfn(HYPERVISOR_VIRT_START))
516 {
517 printk("WARNING: Mini-OS trying to use Xen virtual space. "
518 "Truncating memory from %dMB to ",
519 ((unsigned long)pfn_to_virt(*max_pfn) - (unsigned long)&_text)>>20);
520 *max_pfn = virt_to_pfn(HYPERVISOR_VIRT_START - PAGE_SIZE);
521 printk("%dMB\n",
522 ((unsigned long)pfn_to_virt(*max_pfn) - (unsigned long)&_text)>>20);
523 }
525 start_address = (unsigned long)pfn_to_virt(pfn_to_map);
526 end_address = (unsigned long)pfn_to_virt(*max_pfn);
528 /* We worked out the virtual memory range to map, now mapping loop */
529 printk("Mapping memory range 0x%lx - 0x%lx\n", start_address, end_address);
531 while(start_address < end_address)
532 {
533 tab = (pgentry_t *)start_info.pt_base;
534 mfn = pfn_to_mfn(virt_to_pfn(start_info.pt_base));
536 #if defined(__x86_64__)
537 offset = l4_table_offset(start_address);
538 /* Need new L3 pt frame */
539 if(!(start_address & L3_MASK))
540 if(need_pt_frame(start_address, L3_FRAME))
541 new_pt_frame(&pt_pfn, mfn, offset, L3_FRAME);
543 page = tab[offset];
544 mfn = pte_to_mfn(page);
545 tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
546 #endif
547 #if defined(__x86_64__) || defined(CONFIG_X86_PAE)
548 offset = l3_table_offset(start_address);
549 /* Need new L2 pt frame */
550 if(!(start_address & L2_MASK))
551 if(need_pt_frame(start_address, L2_FRAME))
552 new_pt_frame(&pt_pfn, mfn, offset, L2_FRAME);
554 page = tab[offset];
555 mfn = pte_to_mfn(page);
556 tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
557 #endif
558 offset = l2_table_offset(start_address);
559 /* Need new L1 pt frame */
560 if(!(start_address & L1_MASK))
561 if(need_pt_frame(start_address, L1_FRAME))
562 new_pt_frame(&pt_pfn, mfn, offset, L1_FRAME);
564 page = tab[offset];
565 mfn = pte_to_mfn(page);
566 offset = l1_table_offset(start_address);
568 mmu_updates[count].ptr = ((pgentry_t)mfn << PAGE_SHIFT) + sizeof(pgentry_t) * offset;
569 mmu_updates[count].val = (pgentry_t)pfn_to_mfn(pfn_to_map++) << PAGE_SHIFT | L1_PROT;
570 count++;
571 if (count == L1_PAGETABLE_ENTRIES || pfn_to_map == *max_pfn)
572 {
573 if(HYPERVISOR_mmu_update(mmu_updates, count, NULL, DOMID_SELF) < 0)
574 {
575 printk("PTE could not be updated\n");
576 do_exit();
577 }
578 count = 0;
579 }
580 start_address += PAGE_SIZE;
581 }
582 *start_pfn = pt_pfn;
583 }
586 void mem_test(unsigned long *start_add, unsigned long *end_add)
587 {
588 unsigned long mask = 0x10000;
589 unsigned long *pointer;
591 for(pointer = start_add; pointer < end_add; pointer++)
592 {
593 if(!(((unsigned long)pointer) & 0xfffff))
594 {
595 printk("Writing to %lx\n", pointer);
596 page_walk((unsigned long)pointer);
597 }
598 *pointer = (unsigned long)pointer & ~mask;
599 }
601 for(pointer = start_add; pointer < end_add; pointer++)
602 {
603 if(((unsigned long)pointer & ~mask) != *pointer)
604 printk("Read error at 0x%lx. Read: 0x%lx, should read 0x%lx\n",
605 (unsigned long)pointer,
606 *pointer,
607 ((unsigned long)pointer & ~mask));
608 }
610 }
612 static pgentry_t *demand_map_pgt;
613 static void *demand_map_area_start;
615 static void init_demand_mapping_area(unsigned long max_pfn)
616 {
617 unsigned long mfn;
618 pgentry_t *tab;
619 unsigned long start_addr;
620 unsigned long pt_pfn;
621 unsigned offset;
623 /* Round up to four megs. + 1024 rather than + 1023 since we want
624 to be sure we don't end up in the same place we started. */
625 max_pfn = (max_pfn + L1_PAGETABLE_ENTRIES) & ~(L1_PAGETABLE_ENTRIES - 1);
626 if (max_pfn == 0 ||
627 (unsigned long)pfn_to_virt(max_pfn + L1_PAGETABLE_ENTRIES) >=
628 HYPERVISOR_VIRT_START) {
629 printk("Too much memory; no room for demand map hole.\n");
630 do_exit();
631 }
633 demand_map_area_start = pfn_to_virt(max_pfn);
634 printk("Demand map pfns start at %lx (%p).\n", max_pfn,
635 demand_map_area_start);
636 start_addr = (unsigned long)demand_map_area_start;
638 tab = (pgentry_t *)start_info.pt_base;
639 mfn = virt_to_mfn(start_info.pt_base);
640 pt_pfn = virt_to_pfn(alloc_page());
642 #if defined(__x86_64__)
643 offset = l4_table_offset(start_addr);
644 if (!(tab[offset] & _PAGE_PRESENT)) {
645 new_pt_frame(&pt_pfn, mfn, offset, L3_FRAME);
646 pt_pfn = virt_to_pfn(alloc_page());
647 }
648 ASSERT(tab[offset] & _PAGE_PRESENT);
649 mfn = pte_to_mfn(tab[offset]);
650 tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
651 #endif
652 #if defined(__x86_64__) || defined(CONFIG_X86_PAE)
653 offset = l3_table_offset(start_addr);
654 if (!(tab[offset] & _PAGE_PRESENT)) {
655 new_pt_frame(&pt_pfn, mfn, offset, L2_FRAME);
656 pt_pfn = virt_to_pfn(alloc_page());
657 }
658 ASSERT(tab[offset] & _PAGE_PRESENT);
659 mfn = pte_to_mfn(tab[offset]);
660 tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
661 #endif
662 offset = l2_table_offset(start_addr);
663 if (tab[offset] & _PAGE_PRESENT) {
664 printk("Demand map area already has a page table covering it?\n");
665 BUG();
666 }
667 demand_map_pgt = pfn_to_virt(pt_pfn);
668 new_pt_frame(&pt_pfn, mfn, offset, L1_FRAME);
669 ASSERT(tab[offset] & _PAGE_PRESENT);
670 }
672 void *map_frames(unsigned long *f, unsigned long n)
673 {
674 unsigned long x;
675 unsigned long y = 0;
676 mmu_update_t mmu_updates[16];
677 int rc;
679 if (n > 16) {
680 printk("Tried to map too many (%ld) frames at once.\n", n);
681 return NULL;
682 }
684 /* Find a run of n contiguous frames */
685 for (x = 0; x <= 1024 - n; x += y + 1) {
686 for (y = 0; y < n; y++)
687 if (demand_map_pgt[x+y] & _PAGE_PRESENT)
688 break;
689 if (y == n)
690 break;
691 }
692 if (y != n) {
693 printk("Failed to map %ld frames!\n", n);
694 return NULL;
695 }
697 /* Found it at x. Map it in. */
698 for (y = 0; y < n; y++) {
699 mmu_updates[y].ptr = virt_to_mach(&demand_map_pgt[x + y]);
700 mmu_updates[y].val = (f[y] << PAGE_SHIFT) | L1_PROT;
701 }
703 rc = HYPERVISOR_mmu_update(mmu_updates, n, NULL, DOMID_SELF);
704 if (rc < 0) {
705 printk("Map %ld failed: %d.\n", n, rc);
706 return NULL;
707 } else {
708 return (void *)(unsigned long)((unsigned long)demand_map_area_start +
709 x * PAGE_SIZE);
710 }
711 }
713 void init_mm(void)
714 {
716 unsigned long start_pfn, max_pfn;
718 printk("MM: Init\n");
720 printk(" _text: %p\n", &_text);
721 printk(" _etext: %p\n", &_etext);
722 printk(" _edata: %p\n", &_edata);
723 printk(" stack start: %p\n", &stack);
724 printk(" _end: %p\n", &_end);
726 /* First page follows page table pages and 3 more pages (store page etc) */
727 start_pfn = PFN_UP(to_phys(start_info.pt_base)) +
728 start_info.nr_pt_frames + 3;
729 max_pfn = start_info.nr_pages;
731 printk(" start_pfn: %lx\n", start_pfn);
732 printk(" max_pfn: %lx\n", max_pfn);
734 build_pagetable(&start_pfn, &max_pfn);
736 /*
737 * now we can initialise the page allocator
738 */
739 printk("MM: Initialise page allocator for %lx(%lx)-%lx(%lx)\n",
740 (u_long)to_virt(PFN_PHYS(start_pfn)), PFN_PHYS(start_pfn),
741 (u_long)to_virt(PFN_PHYS(max_pfn)), PFN_PHYS(max_pfn));
742 init_page_allocator(PFN_PHYS(start_pfn), PFN_PHYS(max_pfn));
743 printk("MM: done\n");
745 init_demand_mapping_area(max_pfn);
746 printk("Initialised demand area.\n");
747 }
749 void sanity_check(void)
750 {
751 int x;
752 chunk_head_t *head;
754 for (x = 0; x < FREELIST_SIZE; x++) {
755 for (head = free_head[x]; !FREELIST_EMPTY(head); head = head->next) {
756 ASSERT(!allocated_in_map(virt_to_pfn(head)));
757 if (head->next)
758 ASSERT(head->next->pprev == &head->next);
759 }
760 if (free_head[x]) {
761 ASSERT(free_head[x]->pprev == &free_head[x]);
762 }
763 }
764 }