|
|
1.1 root 1: /*
2: * Copyright (c) 2010-2014 Richard Braun.
3: *
4: * This program is free software: you can redistribute it and/or modify
5: * it under the terms of the GNU General Public License as published by
6: * the Free Software Foundation, either version 2 of the License, or
7: * (at your option) any later version.
8: *
9: * This program is distributed in the hope that it will be useful,
10: * but WITHOUT ANY WARRANTY; without even the implied warranty of
11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: * GNU General Public License for more details.
13: *
14: * You should have received a copy of the GNU General Public License
15: * along with this program. If not, see <http://www.gnu.org/licenses/>.
16: */
17:
18: #include <string.h>
19: #include <i386/model_dep.h>
20: #include <i386at/biosmem.h>
21: #include <kern/assert.h>
22: #include <kern/debug.h>
23: #include <kern/macros.h>
24: #include <kern/printf.h>
25: #include <mach/vm_param.h>
26: #include <mach/xen.h>
27: #include <mach/machine/multiboot.h>
28: #include <sys/types.h>
29: #include <vm/vm_page.h>
30:
1.1.1.2 ! root 31: #define DEBUG 0
! 32:
1.1 root 33: #define __boot
34: #define __bootdata
35: #define __init
36:
37: #define boot_memmove memmove
1.1.1.2 ! root 38: #define boot_panic(s) panic("%s", s)
1.1 root 39: #define boot_strlen strlen
40:
41: #define BOOT_CGAMEM phystokv(0xb8000)
42: #define BOOT_CGACHARS (80 * 25)
43: #define BOOT_CGACOLOR 0x7
44:
1.1.1.2 ! root 45: #define BIOSMEM_MAX_BOOT_DATA 64
! 46:
! 47: /*
! 48: * Boot data descriptor.
! 49: *
! 50: * The start and end addresses must not be page-aligned, since there
! 51: * could be more than one range inside a single page.
! 52: */
! 53: struct biosmem_boot_data {
! 54: phys_addr_t start;
! 55: phys_addr_t end;
! 56: boolean_t temporary;
! 57: };
! 58:
! 59: /*
! 60: * Sorted array of boot data descriptors.
! 61: */
! 62: static struct biosmem_boot_data biosmem_boot_data_array[BIOSMEM_MAX_BOOT_DATA]
! 63: __bootdata;
! 64: static unsigned int biosmem_nr_boot_data __bootdata;
1.1 root 65:
66: /*
67: * Maximum number of entries in the BIOS memory map.
68: *
69: * Because of adjustments of overlapping ranges, the memory map can grow
70: * to twice this size.
71: */
72: #define BIOSMEM_MAX_MAP_SIZE 128
73:
74: /*
75: * Memory range types.
76: */
77: #define BIOSMEM_TYPE_AVAILABLE 1
78: #define BIOSMEM_TYPE_RESERVED 2
79: #define BIOSMEM_TYPE_ACPI 3
80: #define BIOSMEM_TYPE_NVS 4
81: #define BIOSMEM_TYPE_UNUSABLE 5
82: #define BIOSMEM_TYPE_DISABLED 6
83:
84: /*
85: * Memory map entry.
86: */
87: struct biosmem_map_entry {
88: uint64_t base_addr;
89: uint64_t length;
90: unsigned int type;
91: };
92:
93: /*
94: * Memory map built from the information passed by the boot loader.
95: *
96: * If the boot loader didn't pass a valid memory map, a simple map is built
97: * based on the mem_lower and mem_upper multiboot fields.
98: */
99: static struct biosmem_map_entry biosmem_map[BIOSMEM_MAX_MAP_SIZE * 2]
100: __bootdata;
101: static unsigned int biosmem_map_size __bootdata;
102:
103: /*
1.1.1.2 ! root 104: * Contiguous block of physical memory.
! 105: */
! 106: struct biosmem_segment {
! 107: phys_addr_t start;
! 108: phys_addr_t end;
! 109: };
! 110:
! 111: /*
1.1 root 112: * Physical segment boundaries.
113: */
114: static struct biosmem_segment biosmem_segments[VM_PAGE_MAX_SEGS] __bootdata;
115:
116: /*
117: * Boundaries of the simple bootstrap heap.
118: *
119: * This heap is located above BIOS memory.
120: */
1.1.1.2 ! root 121: static phys_addr_t biosmem_heap_start __bootdata;
! 122: static phys_addr_t biosmem_heap_bottom __bootdata;
! 123: static phys_addr_t biosmem_heap_top __bootdata;
! 124: static phys_addr_t biosmem_heap_end __bootdata;
! 125:
! 126: /*
! 127: * Boot allocation policy.
! 128: *
! 129: * Top-down allocations are normally preferred to avoid unnecessarily
! 130: * filling the DMA segment.
! 131: */
! 132: static boolean_t biosmem_heap_topdown __bootdata;
1.1 root 133:
1.1.1.2 ! root 134: static char biosmem_panic_inval_boot_data[] __bootdata
! 135: = "biosmem: invalid boot data";
! 136: static char biosmem_panic_too_many_boot_data[] __bootdata
! 137: = "biosmem: too many boot data ranges";
! 138: static char biosmem_panic_too_big_msg[] __bootdata
1.1 root 139: = "biosmem: too many memory map entries";
140: #ifndef MACH_HYP
141: static char biosmem_panic_setup_msg[] __bootdata
142: = "biosmem: unable to set up the early memory allocator";
143: #endif /* MACH_HYP */
144: static char biosmem_panic_noseg_msg[] __bootdata
145: = "biosmem: unable to find any memory segment";
146: static char biosmem_panic_inval_msg[] __bootdata
147: = "biosmem: attempt to allocate 0 page";
148: static char biosmem_panic_nomem_msg[] __bootdata
149: = "biosmem: unable to allocate memory";
150:
1.1.1.2 ! root 151: void __boot
! 152: biosmem_register_boot_data(phys_addr_t start, phys_addr_t end,
! 153: boolean_t temporary)
! 154: {
! 155: unsigned int i;
! 156:
! 157: if (start >= end) {
! 158: boot_panic(biosmem_panic_inval_boot_data);
! 159: }
! 160:
! 161: if (biosmem_nr_boot_data == ARRAY_SIZE(biosmem_boot_data_array)) {
! 162: boot_panic(biosmem_panic_too_many_boot_data);
! 163: }
! 164:
! 165: for (i = 0; i < biosmem_nr_boot_data; i++) {
! 166: /* Check if the new range overlaps */
! 167: if ((end > biosmem_boot_data_array[i].start)
! 168: && (start < biosmem_boot_data_array[i].end)) {
! 169:
! 170: /*
! 171: * If it does, check whether it's part of another range.
! 172: * For example, this applies to debugging symbols directly
! 173: * taken from the kernel image.
! 174: */
! 175: if ((start >= biosmem_boot_data_array[i].start)
! 176: && (end <= biosmem_boot_data_array[i].end)) {
! 177:
! 178: /*
! 179: * If it's completely included, make sure that a permanent
! 180: * range remains permanent.
! 181: *
! 182: * XXX This means that if one big range is first registered
! 183: * as temporary, and a smaller range inside of it is
! 184: * registered as permanent, the bigger range becomes
! 185: * permanent. It's not easy nor useful in practice to do
! 186: * better than that.
! 187: */
! 188: if (biosmem_boot_data_array[i].temporary != temporary) {
! 189: biosmem_boot_data_array[i].temporary = FALSE;
! 190: }
! 191:
! 192: return;
! 193: }
! 194:
! 195: boot_panic(biosmem_panic_inval_boot_data);
! 196: }
! 197:
! 198: if (end <= biosmem_boot_data_array[i].start) {
! 199: break;
! 200: }
! 201: }
! 202:
! 203: boot_memmove(&biosmem_boot_data_array[i + 1],
! 204: &biosmem_boot_data_array[i],
! 205: (biosmem_nr_boot_data - i) * sizeof(*biosmem_boot_data_array));
! 206:
! 207: biosmem_boot_data_array[i].start = start;
! 208: biosmem_boot_data_array[i].end = end;
! 209: biosmem_boot_data_array[i].temporary = temporary;
! 210: biosmem_nr_boot_data++;
! 211: }
! 212:
! 213: static void __init
! 214: biosmem_unregister_boot_data(phys_addr_t start, phys_addr_t end)
! 215: {
! 216: unsigned int i;
! 217:
! 218: if (start >= end) {
! 219: panic("%s", biosmem_panic_inval_boot_data);
! 220: }
! 221:
! 222: assert(biosmem_nr_boot_data != 0);
! 223:
! 224: for (i = 0; biosmem_nr_boot_data; i++) {
! 225: if ((start == biosmem_boot_data_array[i].start)
! 226: && (end == biosmem_boot_data_array[i].end)) {
! 227: break;
! 228: }
! 229: }
! 230:
! 231: if (i == biosmem_nr_boot_data) {
! 232: return;
! 233: }
! 234:
! 235: #if DEBUG
! 236: printf("biosmem: unregister boot data: %llx:%llx\n",
! 237: (unsigned long long)biosmem_boot_data_array[i].start,
! 238: (unsigned long long)biosmem_boot_data_array[i].end);
! 239: #endif /* DEBUG */
! 240:
! 241: biosmem_nr_boot_data--;
! 242:
! 243: boot_memmove(&biosmem_boot_data_array[i],
! 244: &biosmem_boot_data_array[i + 1],
! 245: (biosmem_nr_boot_data - i) * sizeof(*biosmem_boot_data_array));
! 246: }
! 247:
1.1 root 248: #ifndef MACH_HYP
249:
250: static void __boot
251: biosmem_map_build(const struct multiboot_raw_info *mbi)
252: {
253: struct multiboot_raw_mmap_entry *mb_entry, *mb_end;
254: struct biosmem_map_entry *start, *entry, *end;
255: unsigned long addr;
256:
257: addr = phystokv(mbi->mmap_addr);
258: mb_entry = (struct multiboot_raw_mmap_entry *)addr;
259: mb_end = (struct multiboot_raw_mmap_entry *)(addr + mbi->mmap_length);
260: start = biosmem_map;
261: entry = start;
262: end = entry + BIOSMEM_MAX_MAP_SIZE;
263:
264: while ((mb_entry < mb_end) && (entry < end)) {
265: entry->base_addr = mb_entry->base_addr;
266: entry->length = mb_entry->length;
267: entry->type = mb_entry->type;
268:
269: mb_entry = (void *)mb_entry + sizeof(mb_entry->size) + mb_entry->size;
270: entry++;
271: }
272:
273: biosmem_map_size = entry - start;
274: }
275:
276: static void __boot
277: biosmem_map_build_simple(const struct multiboot_raw_info *mbi)
278: {
279: struct biosmem_map_entry *entry;
280:
281: entry = biosmem_map;
282: entry->base_addr = 0;
283: entry->length = mbi->mem_lower << 10;
284: entry->type = BIOSMEM_TYPE_AVAILABLE;
285:
286: entry++;
287: entry->base_addr = BIOSMEM_END;
288: entry->length = mbi->mem_upper << 10;
289: entry->type = BIOSMEM_TYPE_AVAILABLE;
290:
291: biosmem_map_size = 2;
292: }
293:
294: #endif /* MACH_HYP */
295:
296: static int __boot
297: biosmem_map_entry_is_invalid(const struct biosmem_map_entry *entry)
298: {
299: return (entry->base_addr + entry->length) <= entry->base_addr;
300: }
301:
302: static void __boot
303: biosmem_map_filter(void)
304: {
305: struct biosmem_map_entry *entry;
306: unsigned int i;
307:
308: i = 0;
309:
310: while (i < biosmem_map_size) {
311: entry = &biosmem_map[i];
312:
313: if (biosmem_map_entry_is_invalid(entry)) {
314: biosmem_map_size--;
315: boot_memmove(entry, entry + 1,
316: (biosmem_map_size - i) * sizeof(*entry));
317: continue;
318: }
319:
320: i++;
321: }
322: }
323:
324: static void __boot
325: biosmem_map_sort(void)
326: {
327: struct biosmem_map_entry tmp;
328: unsigned int i, j;
329:
330: /*
331: * Simple insertion sort.
332: */
333: for (i = 1; i < biosmem_map_size; i++) {
334: tmp = biosmem_map[i];
335:
336: for (j = i - 1; j < i; j--) {
337: if (biosmem_map[j].base_addr < tmp.base_addr)
338: break;
339:
340: biosmem_map[j + 1] = biosmem_map[j];
341: }
342:
343: biosmem_map[j + 1] = tmp;
344: }
345: }
346:
347: static void __boot
348: biosmem_map_adjust(void)
349: {
350: struct biosmem_map_entry tmp, *a, *b, *first, *second;
351: uint64_t a_end, b_end, last_end;
352: unsigned int i, j, last_type;
353:
354: biosmem_map_filter();
355:
356: /*
357: * Resolve overlapping areas, giving priority to most restrictive
358: * (i.e. numerically higher) types.
359: */
360: for (i = 0; i < biosmem_map_size; i++) {
361: a = &biosmem_map[i];
362: a_end = a->base_addr + a->length;
363:
364: j = i + 1;
365:
366: while (j < biosmem_map_size) {
367: b = &biosmem_map[j];
368: b_end = b->base_addr + b->length;
369:
370: if ((a->base_addr >= b_end) || (a_end <= b->base_addr)) {
371: j++;
372: continue;
373: }
374:
375: if (a->base_addr < b->base_addr) {
376: first = a;
377: second = b;
378: } else {
379: first = b;
380: second = a;
381: }
382:
383: if (a_end > b_end) {
384: last_end = a_end;
385: last_type = a->type;
386: } else {
387: last_end = b_end;
388: last_type = b->type;
389: }
390:
391: tmp.base_addr = second->base_addr;
392: tmp.length = MIN(a_end, b_end) - tmp.base_addr;
393: tmp.type = MAX(a->type, b->type);
394: first->length = tmp.base_addr - first->base_addr;
395: second->base_addr += tmp.length;
396: second->length = last_end - second->base_addr;
397: second->type = last_type;
398:
399: /*
400: * Filter out invalid entries.
401: */
402: if (biosmem_map_entry_is_invalid(a)
403: && biosmem_map_entry_is_invalid(b)) {
404: *a = tmp;
405: biosmem_map_size--;
406: memmove(b, b + 1, (biosmem_map_size - j) * sizeof(*b));
407: continue;
408: } else if (biosmem_map_entry_is_invalid(a)) {
409: *a = tmp;
410: j++;
411: continue;
412: } else if (biosmem_map_entry_is_invalid(b)) {
413: *b = tmp;
414: j++;
415: continue;
416: }
417:
418: if (tmp.type == a->type)
419: first = a;
420: else if (tmp.type == b->type)
421: first = b;
422: else {
423:
424: /*
425: * If the overlapping area can't be merged with one of its
426: * neighbors, it must be added as a new entry.
427: */
428:
429: if (biosmem_map_size >= ARRAY_SIZE(biosmem_map))
1.1.1.2 ! root 430: boot_panic(biosmem_panic_too_big_msg);
1.1 root 431:
432: biosmem_map[biosmem_map_size] = tmp;
433: biosmem_map_size++;
434: j++;
435: continue;
436: }
437:
438: if (first->base_addr > tmp.base_addr)
439: first->base_addr = tmp.base_addr;
440:
441: first->length += tmp.length;
442: j++;
443: }
444: }
445:
446: biosmem_map_sort();
447: }
448:
1.1.1.2 ! root 449: /*
! 450: * Find addresses of physical memory within a given range.
! 451: *
! 452: * This function considers the memory map with the [*phys_start, *phys_end]
! 453: * range on entry, and returns the lowest address of physical memory
! 454: * in *phys_start, and the highest address of unusable memory immediately
! 455: * following physical memory in *phys_end.
! 456: *
! 457: * These addresses are normally used to establish the range of a segment.
! 458: */
1.1 root 459: static int __boot
460: biosmem_map_find_avail(phys_addr_t *phys_start, phys_addr_t *phys_end)
461: {
462: const struct biosmem_map_entry *entry, *map_end;
463: phys_addr_t seg_start, seg_end;
464: uint64_t start, end;
465:
466: seg_start = (phys_addr_t)-1;
467: seg_end = (phys_addr_t)-1;
468: map_end = biosmem_map + biosmem_map_size;
469:
470: for (entry = biosmem_map; entry < map_end; entry++) {
471: if (entry->type != BIOSMEM_TYPE_AVAILABLE)
472: continue;
473:
474: start = vm_page_round(entry->base_addr);
475:
476: if (start >= *phys_end)
477: break;
478:
479: end = vm_page_trunc(entry->base_addr + entry->length);
480:
481: if ((start < end) && (start < *phys_end) && (end > *phys_start)) {
482: if (seg_start == (phys_addr_t)-1)
483: seg_start = start;
484:
485: seg_end = end;
486: }
487: }
488:
489: if ((seg_start == (phys_addr_t)-1) || (seg_end == (phys_addr_t)-1))
490: return -1;
491:
492: if (seg_start > *phys_start)
493: *phys_start = seg_start;
494:
495: if (seg_end < *phys_end)
496: *phys_end = seg_end;
497:
498: return 0;
499: }
500:
501: static void __boot
502: biosmem_set_segment(unsigned int seg_index, phys_addr_t start, phys_addr_t end)
503: {
504: biosmem_segments[seg_index].start = start;
505: biosmem_segments[seg_index].end = end;
506: }
507:
508: static phys_addr_t __boot
509: biosmem_segment_end(unsigned int seg_index)
510: {
511: return biosmem_segments[seg_index].end;
512: }
513:
514: static phys_addr_t __boot
515: biosmem_segment_size(unsigned int seg_index)
516: {
517: return biosmem_segments[seg_index].end - biosmem_segments[seg_index].start;
518: }
519:
1.1.1.2 ! root 520: static int __boot
! 521: biosmem_find_avail_clip(phys_addr_t *avail_start, phys_addr_t *avail_end,
! 522: phys_addr_t data_start, phys_addr_t data_end)
1.1 root 523: {
1.1.1.2 ! root 524: phys_addr_t orig_end;
1.1 root 525:
1.1.1.2 ! root 526: assert(data_start < data_end);
1.1 root 527:
1.1.1.2 ! root 528: orig_end = data_end;
! 529: data_start = vm_page_trunc(data_start);
! 530: data_end = vm_page_round(data_end);
1.1 root 531:
1.1.1.2 ! root 532: if (data_end < orig_end) {
! 533: boot_panic(biosmem_panic_inval_boot_data);
! 534: }
1.1 root 535:
1.1.1.2 ! root 536: if ((data_end <= *avail_start) || (data_start >= *avail_end)) {
! 537: return 0;
1.1 root 538: }
539:
1.1.1.2 ! root 540: if (data_start > *avail_start) {
! 541: *avail_end = data_start;
! 542: } else {
! 543: if (data_end >= *avail_end) {
! 544: return -1;
! 545: }
! 546:
! 547: *avail_start = data_end;
1.1 root 548: }
1.1.1.2 ! root 549:
! 550: return 0;
1.1 root 551: }
552:
553: /*
1.1.1.2 ! root 554: * Find available memory in the given range.
! 555: *
! 556: * The search starts at the given start address, up to the given end address.
! 557: * If a range is found, it is stored through the avail_startp and avail_endp
! 558: * pointers.
1.1 root 559: *
1.1.1.2 ! root 560: * The range boundaries are page-aligned on return.
1.1 root 561: */
1.1.1.2 ! root 562: static int __boot
! 563: biosmem_find_avail(phys_addr_t start, phys_addr_t end,
! 564: phys_addr_t *avail_start, phys_addr_t *avail_end)
1.1 root 565: {
1.1.1.2 ! root 566: phys_addr_t orig_start;
! 567: unsigned int i;
! 568: int error;
1.1 root 569:
1.1.1.2 ! root 570: assert(start <= end);
1.1 root 571:
1.1.1.2 ! root 572: orig_start = start;
! 573: start = vm_page_round(start);
! 574: end = vm_page_trunc(end);
1.1 root 575:
1.1.1.2 ! root 576: if ((start < orig_start) || (start >= end)) {
! 577: return -1;
1.1 root 578: }
579:
1.1.1.2 ! root 580: *avail_start = start;
! 581: *avail_end = end;
1.1 root 582:
1.1.1.2 ! root 583: for (i = 0; i < biosmem_nr_boot_data; i++) {
! 584: error = biosmem_find_avail_clip(avail_start, avail_end,
! 585: biosmem_boot_data_array[i].start,
! 586: biosmem_boot_data_array[i].end);
1.1 root 587:
1.1.1.2 ! root 588: if (error) {
! 589: return -1;
1.1 root 590: }
591: }
592:
1.1.1.2 ! root 593: return 0;
1.1 root 594: }
595:
1.1.1.2 ! root 596: #ifndef MACH_HYP
! 597:
1.1 root 598: static void __boot
1.1.1.2 ! root 599: biosmem_setup_allocator(const struct multiboot_raw_info *mbi)
1.1 root 600: {
1.1.1.2 ! root 601: phys_addr_t heap_start, heap_end, max_heap_start, max_heap_end;
! 602: phys_addr_t start, end;
! 603: int error;
1.1 root 604:
605: /*
606: * Find some memory for the heap. Look for the largest unused area in
607: * upper memory, carefully avoiding all boot data.
608: */
1.1.1.2 ! root 609: end = vm_page_trunc((mbi->mem_upper + 1024) << 10);
1.1 root 610:
611: #ifndef __LP64__
1.1.1.2 ! root 612: if (end > VM_PAGE_DIRECTMAP_LIMIT)
! 613: end = VM_PAGE_DIRECTMAP_LIMIT;
1.1 root 614: #endif /* __LP64__ */
615:
616: max_heap_start = 0;
617: max_heap_end = 0;
1.1.1.2 ! root 618: start = BIOSMEM_END;
1.1 root 619:
1.1.1.2 ! root 620: for (;;) {
! 621: error = biosmem_find_avail(start, end, &heap_start, &heap_end);
! 622:
! 623: if (error) {
! 624: break;
1.1 root 625: }
626:
627: if ((heap_end - heap_start) > (max_heap_end - max_heap_start)) {
628: max_heap_start = heap_start;
629: max_heap_end = heap_end;
630: }
631:
1.1.1.2 ! root 632: start = heap_end;
! 633: }
1.1 root 634:
635: if (max_heap_start >= max_heap_end)
636: boot_panic(biosmem_panic_setup_msg);
637:
638: biosmem_heap_start = max_heap_start;
639: biosmem_heap_end = max_heap_end;
1.1.1.2 ! root 640: biosmem_heap_bottom = biosmem_heap_start;
! 641: biosmem_heap_top = biosmem_heap_end;
! 642: biosmem_heap_topdown = TRUE;
! 643:
! 644: /* Prevent biosmem_free_usable() from releasing the heap */
! 645: biosmem_register_boot_data(biosmem_heap_start, biosmem_heap_end, FALSE);
1.1 root 646: }
647:
648: #endif /* MACH_HYP */
649:
650: static void __boot
651: biosmem_bootstrap_common(void)
652: {
1.1.1.2 ! root 653: phys_addr_t phys_start, phys_end;
1.1 root 654: int error;
655:
656: biosmem_map_adjust();
657:
658: phys_start = BIOSMEM_BASE;
659: phys_end = VM_PAGE_DMA_LIMIT;
660: error = biosmem_map_find_avail(&phys_start, &phys_end);
661:
662: if (error)
663: boot_panic(biosmem_panic_noseg_msg);
664:
665: biosmem_set_segment(VM_PAGE_SEG_DMA, phys_start, phys_end);
666:
667: phys_start = VM_PAGE_DMA_LIMIT;
668: #ifdef VM_PAGE_DMA32_LIMIT
669: phys_end = VM_PAGE_DMA32_LIMIT;
670: error = biosmem_map_find_avail(&phys_start, &phys_end);
671:
672: if (error)
1.1.1.2 ! root 673: return;
1.1 root 674:
675: biosmem_set_segment(VM_PAGE_SEG_DMA32, phys_start, phys_end);
676:
677: phys_start = VM_PAGE_DMA32_LIMIT;
678: #endif /* VM_PAGE_DMA32_LIMIT */
679: phys_end = VM_PAGE_DIRECTMAP_LIMIT;
680: error = biosmem_map_find_avail(&phys_start, &phys_end);
681:
682: if (error)
1.1.1.2 ! root 683: return;
1.1 root 684:
685: biosmem_set_segment(VM_PAGE_SEG_DIRECTMAP, phys_start, phys_end);
686:
687: phys_start = VM_PAGE_DIRECTMAP_LIMIT;
688: phys_end = VM_PAGE_HIGHMEM_LIMIT;
689: error = biosmem_map_find_avail(&phys_start, &phys_end);
690:
691: if (error)
1.1.1.2 ! root 692: return;
1.1 root 693:
694: biosmem_set_segment(VM_PAGE_SEG_HIGHMEM, phys_start, phys_end);
695: }
696:
697: #ifdef MACH_HYP
698:
699: void
700: biosmem_xen_bootstrap(void)
701: {
702: struct biosmem_map_entry *entry;
703:
704: entry = biosmem_map;
705: entry->base_addr = 0;
706: entry->length = boot_info.nr_pages << PAGE_SHIFT;
707: entry->type = BIOSMEM_TYPE_AVAILABLE;
708:
709: biosmem_map_size = 1;
710:
711: biosmem_bootstrap_common();
712:
713: biosmem_heap_start = _kvtophys(boot_info.pt_base)
714: + (boot_info.nr_pt_frames + 3) * 0x1000;
715: biosmem_heap_end = boot_info.nr_pages << PAGE_SHIFT;
716:
717: #ifndef __LP64__
718: if (biosmem_heap_end > VM_PAGE_DIRECTMAP_LIMIT)
719: biosmem_heap_end = VM_PAGE_DIRECTMAP_LIMIT;
720: #endif /* __LP64__ */
721:
1.1.1.2 ! root 722: biosmem_heap_bottom = biosmem_heap_start;
! 723: biosmem_heap_top = biosmem_heap_end;
! 724:
1.1 root 725: /*
1.1.1.2 ! root 726: * XXX Allocation on Xen are initially bottom-up :
1.1 root 727: * At the "start of day", only 512k are available after the boot
728: * data. The pmap module then creates a 4g mapping so all physical
729: * memory is available, but it uses this allocator to do so.
730: * Therefore, it must return pages from this small 512k regions
731: * first.
732: */
1.1.1.2 ! root 733: biosmem_heap_topdown = FALSE;
! 734:
! 735: /*
! 736: * Prevent biosmem_free_usable() from releasing the Xen boot information
! 737: * and the heap.
! 738: */
! 739: biosmem_register_boot_data(0, biosmem_heap_end, FALSE);
1.1 root 740: }
741:
742: #else /* MACH_HYP */
743:
744: void __boot
1.1.1.2 ! root 745: biosmem_bootstrap(const struct multiboot_raw_info *mbi)
1.1 root 746: {
747: if (mbi->flags & MULTIBOOT_LOADER_MMAP)
748: biosmem_map_build(mbi);
749: else
750: biosmem_map_build_simple(mbi);
751:
752: biosmem_bootstrap_common();
753: biosmem_setup_allocator(mbi);
754: }
755:
756: #endif /* MACH_HYP */
757:
758: unsigned long __boot
759: biosmem_bootalloc(unsigned int nr_pages)
760: {
761: unsigned long addr, size;
762:
763: size = vm_page_ptoa(nr_pages);
764:
765: if (size == 0)
766: boot_panic(biosmem_panic_inval_msg);
767:
1.1.1.2 ! root 768: if (biosmem_heap_topdown) {
! 769: addr = biosmem_heap_top - size;
1.1 root 770:
1.1.1.2 ! root 771: if ((addr < biosmem_heap_start) || (addr > biosmem_heap_top)) {
! 772: boot_panic(biosmem_panic_nomem_msg);
! 773: }
1.1 root 774:
1.1.1.2 ! root 775: biosmem_heap_top = addr;
! 776: } else {
! 777: unsigned long end;
! 778:
! 779: addr = biosmem_heap_bottom;
! 780: end = addr + size;
! 781:
! 782: if ((end > biosmem_heap_end) || (end < biosmem_heap_bottom)) {
! 783: boot_panic(biosmem_panic_nomem_msg);
! 784: }
! 785:
! 786: biosmem_heap_bottom = end;
! 787: }
1.1 root 788:
789: return addr;
790: }
791:
792: phys_addr_t __boot
1.1.1.2 ! root 793: biosmem_directmap_end(void)
1.1 root 794: {
795: if (biosmem_segment_size(VM_PAGE_SEG_DIRECTMAP) != 0)
796: return biosmem_segment_end(VM_PAGE_SEG_DIRECTMAP);
797: else if (biosmem_segment_size(VM_PAGE_SEG_DMA32) != 0)
798: return biosmem_segment_end(VM_PAGE_SEG_DMA32);
799: else
800: return biosmem_segment_end(VM_PAGE_SEG_DMA);
801: }
802:
803: static const char * __init
804: biosmem_type_desc(unsigned int type)
805: {
806: switch (type) {
807: case BIOSMEM_TYPE_AVAILABLE:
808: return "available";
809: case BIOSMEM_TYPE_RESERVED:
810: return "reserved";
811: case BIOSMEM_TYPE_ACPI:
812: return "ACPI";
813: case BIOSMEM_TYPE_NVS:
814: return "ACPI NVS";
815: case BIOSMEM_TYPE_UNUSABLE:
816: return "unusable";
817: default:
818: return "unknown (reserved)";
819: }
820: }
821:
822: static void __init
823: biosmem_map_show(void)
824: {
825: const struct biosmem_map_entry *entry, *end;
826:
827: printf("biosmem: physical memory map:\n");
828:
829: for (entry = biosmem_map, end = entry + biosmem_map_size;
830: entry < end;
831: entry++)
832: printf("biosmem: %018llx:%018llx, %s\n", entry->base_addr,
833: entry->base_addr + entry->length,
834: biosmem_type_desc(entry->type));
835:
1.1.1.2 ! root 836: #if DEBUG
! 837: printf("biosmem: heap: %llx:%llx\n",
! 838: (unsigned long long)biosmem_heap_start,
! 839: (unsigned long long)biosmem_heap_end);
! 840: #endif
1.1 root 841: }
842:
843: static void __init
1.1.1.2 ! root 844: biosmem_load_segment(struct biosmem_segment *seg, uint64_t max_phys_end)
1.1 root 845: {
1.1.1.2 ! root 846: phys_addr_t phys_start, phys_end, avail_start, avail_end;
1.1 root 847: unsigned int seg_index;
848:
1.1.1.2 ! root 849: phys_start = seg->start;
! 850: phys_end = seg->end;
1.1 root 851: seg_index = seg - biosmem_segments;
852:
853: if (phys_end > max_phys_end) {
854: if (max_phys_end <= phys_start) {
855: printf("biosmem: warning: segment %s physically unreachable, "
856: "not loaded\n", vm_page_seg_name(seg_index));
857: return;
858: }
859:
860: printf("biosmem: warning: segment %s truncated to %#llx\n",
861: vm_page_seg_name(seg_index), max_phys_end);
862: phys_end = max_phys_end;
863: }
864:
1.1.1.2 ! root 865: vm_page_load(seg_index, phys_start, phys_end);
1.1 root 866:
1.1.1.2 ! root 867: /*
! 868: * Clip the remaining available heap to fit it into the loaded
! 869: * segment if possible.
! 870: */
1.1 root 871:
1.1.1.2 ! root 872: if ((biosmem_heap_top > phys_start) && (biosmem_heap_bottom < phys_end)) {
! 873: if (biosmem_heap_bottom >= phys_start) {
! 874: avail_start = biosmem_heap_bottom;
! 875: } else {
! 876: avail_start = phys_start;
! 877: }
! 878:
! 879: if (biosmem_heap_top <= phys_end) {
! 880: avail_end = biosmem_heap_top;
! 881: } else {
! 882: avail_end = phys_end;
! 883: }
! 884:
! 885: vm_page_load_heap(seg_index, avail_start, avail_end);
! 886: }
1.1 root 887: }
888:
889: void __init
890: biosmem_setup(void)
891: {
892: struct biosmem_segment *seg;
893: unsigned int i;
894:
895: biosmem_map_show();
896:
897: for (i = 0; i < ARRAY_SIZE(biosmem_segments); i++) {
898: if (biosmem_segment_size(i) == 0)
899: break;
900:
901: seg = &biosmem_segments[i];
1.1.1.2 ! root 902: biosmem_load_segment(seg, VM_PAGE_HIGHMEM_LIMIT);
! 903: }
! 904: }
! 905:
! 906: static void __init
! 907: biosmem_unregister_temporary_boot_data(void)
! 908: {
! 909: struct biosmem_boot_data *data;
! 910: unsigned int i;
! 911:
! 912: for (i = 0; i < biosmem_nr_boot_data; i++) {
! 913: data = &biosmem_boot_data_array[i];
! 914:
! 915: if (!data->temporary) {
! 916: continue;
! 917: }
! 918:
! 919: biosmem_unregister_boot_data(data->start, data->end);
! 920: i = (unsigned int)-1;
1.1 root 921: }
922: }
923:
924: static void __init
925: biosmem_free_usable_range(phys_addr_t start, phys_addr_t end)
926: {
927: struct vm_page *page;
928:
1.1.1.2 ! root 929: #if DEBUG
! 930: printf("biosmem: release to vm_page: %llx:%llx (%lluk)\n",
1.1 root 931: (unsigned long long)start, (unsigned long long)end,
932: (unsigned long long)((end - start) >> 10));
1.1.1.2 ! root 933: #endif
1.1 root 934:
935: while (start < end) {
936: page = vm_page_lookup_pa(start);
937: assert(page != NULL);
938: vm_page_manage(page);
939: start += PAGE_SIZE;
940: }
941: }
942:
943: static void __init
944: biosmem_free_usable_entry(phys_addr_t start, phys_addr_t end)
945: {
1.1.1.2 ! root 946: phys_addr_t avail_start, avail_end;
! 947: int error;
1.1 root 948:
949: for (;;) {
1.1.1.2 ! root 950: error = biosmem_find_avail(start, end, &avail_start, &avail_end);
1.1 root 951:
1.1.1.2 ! root 952: if (error) {
! 953: break;
! 954: }
1.1 root 955:
1.1.1.2 ! root 956: biosmem_free_usable_range(avail_start, avail_end);
! 957: start = avail_end;
1.1 root 958: }
959: }
960:
961: void __init
962: biosmem_free_usable(void)
963: {
964: struct biosmem_map_entry *entry;
965: uint64_t start, end;
966: unsigned int i;
967:
1.1.1.2 ! root 968: biosmem_unregister_temporary_boot_data();
! 969:
1.1 root 970: for (i = 0; i < biosmem_map_size; i++) {
971: entry = &biosmem_map[i];
972:
973: if (entry->type != BIOSMEM_TYPE_AVAILABLE)
974: continue;
975:
976: start = vm_page_round(entry->base_addr);
977:
978: if (start >= VM_PAGE_HIGHMEM_LIMIT)
979: break;
980:
981: end = vm_page_trunc(entry->base_addr + entry->length);
982:
1.1.1.2 ! root 983: if (end > VM_PAGE_HIGHMEM_LIMIT) {
! 984: end = VM_PAGE_HIGHMEM_LIMIT;
! 985: }
! 986:
1.1 root 987: if (start < BIOSMEM_BASE)
988: start = BIOSMEM_BASE;
989:
1.1.1.2 ! root 990: if (start >= end) {
! 991: continue;
! 992: }
! 993:
1.1 root 994: biosmem_free_usable_entry(start, end);
995: }
996: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.