|
|
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 <i386at/elf.h>
22: #include <kern/assert.h>
23: #include <kern/debug.h>
24: #include <kern/macros.h>
25: #include <kern/printf.h>
26: #include <mach/vm_param.h>
27: #include <mach/xen.h>
28: #include <mach/machine/multiboot.h>
29: #include <sys/types.h>
30: #include <vm/vm_page.h>
31:
32: #define __boot
33: #define __bootdata
34: #define __init
35:
36: #define boot_memmove memmove
37: #define boot_panic panic
38: #define boot_strlen strlen
39:
40: #define BOOT_CGAMEM phystokv(0xb8000)
41: #define BOOT_CGACHARS (80 * 25)
42: #define BOOT_CGACOLOR 0x7
43:
44: extern char _start, _end;
45:
46: /*
47: * Maximum number of entries in the BIOS memory map.
48: *
49: * Because of adjustments of overlapping ranges, the memory map can grow
50: * to twice this size.
51: */
52: #define BIOSMEM_MAX_MAP_SIZE 128
53:
54: /*
55: * Memory range types.
56: */
57: #define BIOSMEM_TYPE_AVAILABLE 1
58: #define BIOSMEM_TYPE_RESERVED 2
59: #define BIOSMEM_TYPE_ACPI 3
60: #define BIOSMEM_TYPE_NVS 4
61: #define BIOSMEM_TYPE_UNUSABLE 5
62: #define BIOSMEM_TYPE_DISABLED 6
63:
64: /*
65: * Memory map entry.
66: */
67: struct biosmem_map_entry {
68: uint64_t base_addr;
69: uint64_t length;
70: unsigned int type;
71: };
72:
73: /*
74: * Contiguous block of physical memory.
75: *
76: * Tha "available" range records what has been passed to the VM system as
77: * available inside the segment.
78: */
79: struct biosmem_segment {
80: phys_addr_t start;
81: phys_addr_t end;
82: phys_addr_t avail_start;
83: phys_addr_t avail_end;
84: };
85:
86: /*
87: * Memory map built from the information passed by the boot loader.
88: *
89: * If the boot loader didn't pass a valid memory map, a simple map is built
90: * based on the mem_lower and mem_upper multiboot fields.
91: */
92: static struct biosmem_map_entry biosmem_map[BIOSMEM_MAX_MAP_SIZE * 2]
93: __bootdata;
94: static unsigned int biosmem_map_size __bootdata;
95:
96: /*
97: * Physical segment boundaries.
98: */
99: static struct biosmem_segment biosmem_segments[VM_PAGE_MAX_SEGS] __bootdata;
100:
101: /*
102: * Boundaries of the simple bootstrap heap.
103: *
104: * This heap is located above BIOS memory.
105: */
106: static uint32_t biosmem_heap_start __bootdata;
107: static uint32_t biosmem_heap_cur __bootdata;
108: static uint32_t biosmem_heap_end __bootdata;
109:
110: static char biosmem_panic_toobig_msg[] __bootdata
111: = "biosmem: too many memory map entries";
112: #ifndef MACH_HYP
113: static char biosmem_panic_setup_msg[] __bootdata
114: = "biosmem: unable to set up the early memory allocator";
115: #endif /* MACH_HYP */
116: static char biosmem_panic_noseg_msg[] __bootdata
117: = "biosmem: unable to find any memory segment";
118: static char biosmem_panic_inval_msg[] __bootdata
119: = "biosmem: attempt to allocate 0 page";
120: static char biosmem_panic_nomem_msg[] __bootdata
121: = "biosmem: unable to allocate memory";
122:
123: #ifndef MACH_HYP
124:
125: static void __boot
126: biosmem_map_build(const struct multiboot_raw_info *mbi)
127: {
128: struct multiboot_raw_mmap_entry *mb_entry, *mb_end;
129: struct biosmem_map_entry *start, *entry, *end;
130: unsigned long addr;
131:
132: addr = phystokv(mbi->mmap_addr);
133: mb_entry = (struct multiboot_raw_mmap_entry *)addr;
134: mb_end = (struct multiboot_raw_mmap_entry *)(addr + mbi->mmap_length);
135: start = biosmem_map;
136: entry = start;
137: end = entry + BIOSMEM_MAX_MAP_SIZE;
138:
139: while ((mb_entry < mb_end) && (entry < end)) {
140: entry->base_addr = mb_entry->base_addr;
141: entry->length = mb_entry->length;
142: entry->type = mb_entry->type;
143:
144: mb_entry = (void *)mb_entry + sizeof(mb_entry->size) + mb_entry->size;
145: entry++;
146: }
147:
148: biosmem_map_size = entry - start;
149: }
150:
151: static void __boot
152: biosmem_map_build_simple(const struct multiboot_raw_info *mbi)
153: {
154: struct biosmem_map_entry *entry;
155:
156: entry = biosmem_map;
157: entry->base_addr = 0;
158: entry->length = mbi->mem_lower << 10;
159: entry->type = BIOSMEM_TYPE_AVAILABLE;
160:
161: entry++;
162: entry->base_addr = BIOSMEM_END;
163: entry->length = mbi->mem_upper << 10;
164: entry->type = BIOSMEM_TYPE_AVAILABLE;
165:
166: biosmem_map_size = 2;
167: }
168:
169: #endif /* MACH_HYP */
170:
171: static int __boot
172: biosmem_map_entry_is_invalid(const struct biosmem_map_entry *entry)
173: {
174: return (entry->base_addr + entry->length) <= entry->base_addr;
175: }
176:
177: static void __boot
178: biosmem_map_filter(void)
179: {
180: struct biosmem_map_entry *entry;
181: unsigned int i;
182:
183: i = 0;
184:
185: while (i < biosmem_map_size) {
186: entry = &biosmem_map[i];
187:
188: if (biosmem_map_entry_is_invalid(entry)) {
189: biosmem_map_size--;
190: boot_memmove(entry, entry + 1,
191: (biosmem_map_size - i) * sizeof(*entry));
192: continue;
193: }
194:
195: i++;
196: }
197: }
198:
199: static void __boot
200: biosmem_map_sort(void)
201: {
202: struct biosmem_map_entry tmp;
203: unsigned int i, j;
204:
205: /*
206: * Simple insertion sort.
207: */
208: for (i = 1; i < biosmem_map_size; i++) {
209: tmp = biosmem_map[i];
210:
211: for (j = i - 1; j < i; j--) {
212: if (biosmem_map[j].base_addr < tmp.base_addr)
213: break;
214:
215: biosmem_map[j + 1] = biosmem_map[j];
216: }
217:
218: biosmem_map[j + 1] = tmp;
219: }
220: }
221:
222: static void __boot
223: biosmem_map_adjust(void)
224: {
225: struct biosmem_map_entry tmp, *a, *b, *first, *second;
226: uint64_t a_end, b_end, last_end;
227: unsigned int i, j, last_type;
228:
229: biosmem_map_filter();
230:
231: /*
232: * Resolve overlapping areas, giving priority to most restrictive
233: * (i.e. numerically higher) types.
234: */
235: for (i = 0; i < biosmem_map_size; i++) {
236: a = &biosmem_map[i];
237: a_end = a->base_addr + a->length;
238:
239: j = i + 1;
240:
241: while (j < biosmem_map_size) {
242: b = &biosmem_map[j];
243: b_end = b->base_addr + b->length;
244:
245: if ((a->base_addr >= b_end) || (a_end <= b->base_addr)) {
246: j++;
247: continue;
248: }
249:
250: if (a->base_addr < b->base_addr) {
251: first = a;
252: second = b;
253: } else {
254: first = b;
255: second = a;
256: }
257:
258: if (a_end > b_end) {
259: last_end = a_end;
260: last_type = a->type;
261: } else {
262: last_end = b_end;
263: last_type = b->type;
264: }
265:
266: tmp.base_addr = second->base_addr;
267: tmp.length = MIN(a_end, b_end) - tmp.base_addr;
268: tmp.type = MAX(a->type, b->type);
269: first->length = tmp.base_addr - first->base_addr;
270: second->base_addr += tmp.length;
271: second->length = last_end - second->base_addr;
272: second->type = last_type;
273:
274: /*
275: * Filter out invalid entries.
276: */
277: if (biosmem_map_entry_is_invalid(a)
278: && biosmem_map_entry_is_invalid(b)) {
279: *a = tmp;
280: biosmem_map_size--;
281: memmove(b, b + 1, (biosmem_map_size - j) * sizeof(*b));
282: continue;
283: } else if (biosmem_map_entry_is_invalid(a)) {
284: *a = tmp;
285: j++;
286: continue;
287: } else if (biosmem_map_entry_is_invalid(b)) {
288: *b = tmp;
289: j++;
290: continue;
291: }
292:
293: if (tmp.type == a->type)
294: first = a;
295: else if (tmp.type == b->type)
296: first = b;
297: else {
298:
299: /*
300: * If the overlapping area can't be merged with one of its
301: * neighbors, it must be added as a new entry.
302: */
303:
304: if (biosmem_map_size >= ARRAY_SIZE(biosmem_map))
305: boot_panic(biosmem_panic_toobig_msg);
306:
307: biosmem_map[biosmem_map_size] = tmp;
308: biosmem_map_size++;
309: j++;
310: continue;
311: }
312:
313: if (first->base_addr > tmp.base_addr)
314: first->base_addr = tmp.base_addr;
315:
316: first->length += tmp.length;
317: j++;
318: }
319: }
320:
321: biosmem_map_sort();
322: }
323:
324: static int __boot
325: biosmem_map_find_avail(phys_addr_t *phys_start, phys_addr_t *phys_end)
326: {
327: const struct biosmem_map_entry *entry, *map_end;
328: phys_addr_t seg_start, seg_end;
329: uint64_t start, end;
330:
331: seg_start = (phys_addr_t)-1;
332: seg_end = (phys_addr_t)-1;
333: map_end = biosmem_map + biosmem_map_size;
334:
335: for (entry = biosmem_map; entry < map_end; entry++) {
336: if (entry->type != BIOSMEM_TYPE_AVAILABLE)
337: continue;
338:
339: start = vm_page_round(entry->base_addr);
340:
341: if (start >= *phys_end)
342: break;
343:
344: end = vm_page_trunc(entry->base_addr + entry->length);
345:
346: if ((start < end) && (start < *phys_end) && (end > *phys_start)) {
347: if (seg_start == (phys_addr_t)-1)
348: seg_start = start;
349:
350: seg_end = end;
351: }
352: }
353:
354: if ((seg_start == (phys_addr_t)-1) || (seg_end == (phys_addr_t)-1))
355: return -1;
356:
357: if (seg_start > *phys_start)
358: *phys_start = seg_start;
359:
360: if (seg_end < *phys_end)
361: *phys_end = seg_end;
362:
363: return 0;
364: }
365:
366: static void __boot
367: biosmem_set_segment(unsigned int seg_index, phys_addr_t start, phys_addr_t end)
368: {
369: biosmem_segments[seg_index].start = start;
370: biosmem_segments[seg_index].end = end;
371: }
372:
373: static phys_addr_t __boot
374: biosmem_segment_end(unsigned int seg_index)
375: {
376: return biosmem_segments[seg_index].end;
377: }
378:
379: static phys_addr_t __boot
380: biosmem_segment_size(unsigned int seg_index)
381: {
382: return biosmem_segments[seg_index].end - biosmem_segments[seg_index].start;
383: }
384:
385: #ifndef MACH_HYP
386:
387: static void __boot
388: biosmem_save_cmdline_sizes(struct multiboot_raw_info *mbi)
389: {
390: struct multiboot_raw_module *mod;
391: uint32_t i, va;
392:
393: if (mbi->flags & MULTIBOOT_LOADER_CMDLINE) {
394: va = phystokv(mbi->cmdline);
395: mbi->unused0 = boot_strlen((char *)va) + 1;
396: }
397:
398: if (mbi->flags & MULTIBOOT_LOADER_MODULES) {
399: unsigned long addr;
400:
401: addr = phystokv(mbi->mods_addr);
402:
403: for (i = 0; i < mbi->mods_count; i++) {
404: mod = (struct multiboot_raw_module *)addr + i;
405: va = phystokv(mod->string);
406: mod->reserved = boot_strlen((char *)va) + 1;
407: }
408: }
409: }
410:
411: static void __boot
412: biosmem_find_boot_data_update(uint32_t min, uint32_t *start, uint32_t *end,
413: uint32_t data_start, uint32_t data_end)
414: {
415: if ((min <= data_start) && (data_start < *start)) {
416: *start = data_start;
417: *end = data_end;
418: }
419: }
420:
421: /*
422: * Find the first boot data in the given range, and return their containing
423: * area (start address is returned directly, end address is returned in end).
424: * The following are considered boot data :
425: * - the kernel
426: * - the kernel command line
427: * - the module table
428: * - the modules
429: * - the modules command lines
430: * - the ELF section header table
431: * - the ELF .shstrtab, .symtab and .strtab sections
432: *
433: * If no boot data was found, 0 is returned, and the end address isn't set.
434: */
435: static uint32_t __boot
436: biosmem_find_boot_data(const struct multiboot_raw_info *mbi, uint32_t min,
437: uint32_t max, uint32_t *endp)
438: {
439: struct multiboot_raw_module *mod;
440: struct elf_shdr *shdr;
441: uint32_t i, start, end = end;
442: unsigned long tmp;
443:
444: start = max;
445:
446: biosmem_find_boot_data_update(min, &start, &end, _kvtophys(&_start),
447: _kvtophys(&_end));
448:
449: if ((mbi->flags & MULTIBOOT_LOADER_CMDLINE) && (mbi->cmdline != 0))
450: biosmem_find_boot_data_update(min, &start, &end, mbi->cmdline,
451: mbi->cmdline + mbi->unused0);
452:
453: if (mbi->flags & MULTIBOOT_LOADER_MODULES) {
454: i = mbi->mods_count * sizeof(struct multiboot_raw_module);
455: biosmem_find_boot_data_update(min, &start, &end, mbi->mods_addr,
456: mbi->mods_addr + i);
457: tmp = phystokv(mbi->mods_addr);
458:
459: for (i = 0; i < mbi->mods_count; i++) {
460: mod = (struct multiboot_raw_module *)tmp + i;
461: biosmem_find_boot_data_update(min, &start, &end, mod->mod_start,
462: mod->mod_end);
463:
464: if (mod->string != 0)
465: biosmem_find_boot_data_update(min, &start, &end, mod->string,
466: mod->string + mod->reserved);
467: }
468: }
469:
470: if (mbi->flags & MULTIBOOT_LOADER_SHDR) {
471: tmp = mbi->shdr_num * mbi->shdr_size;
472: biosmem_find_boot_data_update(min, &start, &end, mbi->shdr_addr,
473: mbi->shdr_addr + tmp);
474: tmp = phystokv(mbi->shdr_addr);
475:
476: for (i = 0; i < mbi->shdr_num; i++) {
477: shdr = (struct elf_shdr *)(tmp + (i * mbi->shdr_size));
478:
479: if ((shdr->type != ELF_SHT_SYMTAB)
480: && (shdr->type != ELF_SHT_STRTAB))
481: continue;
482:
483: biosmem_find_boot_data_update(min, &start, &end, shdr->addr,
484: shdr->addr + shdr->size);
485: }
486: }
487:
488: if (start == max)
489: return 0;
490:
491: *endp = end;
492: return start;
493: }
494:
495: static void __boot
496: biosmem_setup_allocator(struct multiboot_raw_info *mbi)
497: {
498: uint32_t heap_start, heap_end, max_heap_start, max_heap_end;
499: uint32_t mem_end, next;
500:
501: /*
502: * Find some memory for the heap. Look for the largest unused area in
503: * upper memory, carefully avoiding all boot data.
504: */
505: mem_end = vm_page_trunc((mbi->mem_upper + 1024) << 10);
506:
507: #ifndef __LP64__
508: if (mem_end > VM_PAGE_DIRECTMAP_LIMIT)
509: mem_end = VM_PAGE_DIRECTMAP_LIMIT;
510: #endif /* __LP64__ */
511:
512: max_heap_start = 0;
513: max_heap_end = 0;
514: next = BIOSMEM_END;
515:
516: do {
517: heap_start = next;
518: heap_end = biosmem_find_boot_data(mbi, heap_start, mem_end, &next);
519:
520: if (heap_end == 0) {
521: heap_end = mem_end;
522: next = 0;
523: }
524:
525: if ((heap_end - heap_start) > (max_heap_end - max_heap_start)) {
526: max_heap_start = heap_start;
527: max_heap_end = heap_end;
528: }
529: } while (next != 0);
530:
531: max_heap_start = vm_page_round(max_heap_start);
532: max_heap_end = vm_page_trunc(max_heap_end);
533:
534: if (max_heap_start >= max_heap_end)
535: boot_panic(biosmem_panic_setup_msg);
536:
537: biosmem_heap_start = max_heap_start;
538: biosmem_heap_end = max_heap_end;
539: biosmem_heap_cur = biosmem_heap_end;
540: }
541:
542: #endif /* MACH_HYP */
543:
544: static void __boot
545: biosmem_bootstrap_common(void)
546: {
547: phys_addr_t phys_start, phys_end, last_addr;
548: int error;
549:
550: biosmem_map_adjust();
551:
552: phys_start = BIOSMEM_BASE;
553: phys_end = VM_PAGE_DMA_LIMIT;
554: error = biosmem_map_find_avail(&phys_start, &phys_end);
555:
556: if (error)
557: boot_panic(biosmem_panic_noseg_msg);
558:
559: biosmem_set_segment(VM_PAGE_SEG_DMA, phys_start, phys_end);
560: last_addr = phys_end;
561:
562: phys_start = VM_PAGE_DMA_LIMIT;
563: #ifdef VM_PAGE_DMA32_LIMIT
564: phys_end = VM_PAGE_DMA32_LIMIT;
565: error = biosmem_map_find_avail(&phys_start, &phys_end);
566:
567: if (error)
568: goto out;
569:
570: biosmem_set_segment(VM_PAGE_SEG_DMA32, phys_start, phys_end);
571: last_addr = phys_end;
572:
573: phys_start = VM_PAGE_DMA32_LIMIT;
574: #endif /* VM_PAGE_DMA32_LIMIT */
575: phys_end = VM_PAGE_DIRECTMAP_LIMIT;
576: error = biosmem_map_find_avail(&phys_start, &phys_end);
577:
578: if (error)
579: goto out;
580:
581: biosmem_set_segment(VM_PAGE_SEG_DIRECTMAP, phys_start, phys_end);
582: last_addr = phys_end;
583:
584: phys_start = VM_PAGE_DIRECTMAP_LIMIT;
585: phys_end = VM_PAGE_HIGHMEM_LIMIT;
586: error = biosmem_map_find_avail(&phys_start, &phys_end);
587:
588: if (error)
589: goto out;
590:
591: biosmem_set_segment(VM_PAGE_SEG_HIGHMEM, phys_start, phys_end);
592:
593: out:
594: /* XXX phys_last_addr must be part of the direct physical mapping */
595: phys_last_addr = last_addr;
596: }
597:
598: #ifdef MACH_HYP
599:
600: void
601: biosmem_xen_bootstrap(void)
602: {
603: struct biosmem_map_entry *entry;
604:
605: entry = biosmem_map;
606: entry->base_addr = 0;
607: entry->length = boot_info.nr_pages << PAGE_SHIFT;
608: entry->type = BIOSMEM_TYPE_AVAILABLE;
609:
610: biosmem_map_size = 1;
611:
612: biosmem_bootstrap_common();
613:
614: biosmem_heap_start = _kvtophys(boot_info.pt_base)
615: + (boot_info.nr_pt_frames + 3) * 0x1000;
616: biosmem_heap_end = boot_info.nr_pages << PAGE_SHIFT;
617:
618: #ifndef __LP64__
619: /* TODO Check that this actually makes sense */
620: if (biosmem_heap_end > VM_PAGE_DIRECTMAP_LIMIT)
621: biosmem_heap_end = VM_PAGE_DIRECTMAP_LIMIT;
622: #endif /* __LP64__ */
623:
624: /*
625: * XXX Allocation on Xen must be bottom-up :
626: * At the "start of day", only 512k are available after the boot
627: * data. The pmap module then creates a 4g mapping so all physical
628: * memory is available, but it uses this allocator to do so.
629: * Therefore, it must return pages from this small 512k regions
630: * first.
631: */
632: biosmem_heap_cur = biosmem_heap_start;
633: }
634:
635: #else /* MACH_HYP */
636:
637: void __boot
638: biosmem_bootstrap(struct multiboot_raw_info *mbi)
639: {
640: if (mbi->flags & MULTIBOOT_LOADER_MMAP)
641: biosmem_map_build(mbi);
642: else
643: biosmem_map_build_simple(mbi);
644:
645: biosmem_bootstrap_common();
646:
647: /*
648: * The kernel and modules command lines will be memory mapped later
649: * during initialization. Their respective sizes must be saved.
650: */
651: biosmem_save_cmdline_sizes(mbi);
652: biosmem_setup_allocator(mbi);
653: }
654:
655: #endif /* MACH_HYP */
656:
657: unsigned long __boot
658: biosmem_bootalloc(unsigned int nr_pages)
659: {
660: unsigned long addr, size;
661:
662: assert(!vm_page_ready());
663:
664: size = vm_page_ptoa(nr_pages);
665:
666: if (size == 0)
667: boot_panic(biosmem_panic_inval_msg);
668:
669: #ifdef MACH_HYP
670: addr = biosmem_heap_cur;
671: #else /* MACH_HYP */
672: /* Top-down allocation to avoid unnecessarily filling DMA segments */
673: addr = biosmem_heap_cur - size;
674: #endif /* MACH_HYP */
675:
676: if ((addr < biosmem_heap_start) || (addr > biosmem_heap_cur))
677: boot_panic(biosmem_panic_nomem_msg);
678:
679: #ifdef MACH_HYP
680: biosmem_heap_cur += size;
681: #else /* MACH_HYP */
682: biosmem_heap_cur = addr;
683: #endif /* MACH_HYP */
684:
685: return addr;
686: }
687:
688: phys_addr_t __boot
689: biosmem_directmap_size(void)
690: {
691: if (biosmem_segment_size(VM_PAGE_SEG_DIRECTMAP) != 0)
692: return biosmem_segment_end(VM_PAGE_SEG_DIRECTMAP);
693: else if (biosmem_segment_size(VM_PAGE_SEG_DMA32) != 0)
694: return biosmem_segment_end(VM_PAGE_SEG_DMA32);
695: else
696: return biosmem_segment_end(VM_PAGE_SEG_DMA);
697: }
698:
699: static const char * __init
700: biosmem_type_desc(unsigned int type)
701: {
702: switch (type) {
703: case BIOSMEM_TYPE_AVAILABLE:
704: return "available";
705: case BIOSMEM_TYPE_RESERVED:
706: return "reserved";
707: case BIOSMEM_TYPE_ACPI:
708: return "ACPI";
709: case BIOSMEM_TYPE_NVS:
710: return "ACPI NVS";
711: case BIOSMEM_TYPE_UNUSABLE:
712: return "unusable";
713: default:
714: return "unknown (reserved)";
715: }
716: }
717:
718: static void __init
719: biosmem_map_show(void)
720: {
721: const struct biosmem_map_entry *entry, *end;
722:
723: printf("biosmem: physical memory map:\n");
724:
725: for (entry = biosmem_map, end = entry + biosmem_map_size;
726: entry < end;
727: entry++)
728: printf("biosmem: %018llx:%018llx, %s\n", entry->base_addr,
729: entry->base_addr + entry->length,
730: biosmem_type_desc(entry->type));
731:
732: printf("biosmem: heap: %x-%x\n", biosmem_heap_start, biosmem_heap_end);
733: }
734:
735: static void __init
736: biosmem_load_segment(struct biosmem_segment *seg, uint64_t max_phys_end,
737: phys_addr_t phys_start, phys_addr_t phys_end,
738: phys_addr_t avail_start, phys_addr_t avail_end)
739: {
740: unsigned int seg_index;
741:
742: seg_index = seg - biosmem_segments;
743:
744: if (phys_end > max_phys_end) {
745: if (max_phys_end <= phys_start) {
746: printf("biosmem: warning: segment %s physically unreachable, "
747: "not loaded\n", vm_page_seg_name(seg_index));
748: return;
749: }
750:
751: printf("biosmem: warning: segment %s truncated to %#llx\n",
752: vm_page_seg_name(seg_index), max_phys_end);
753: phys_end = max_phys_end;
754: }
755:
756: if ((avail_start < phys_start) || (avail_start >= phys_end))
757: avail_start = phys_start;
758:
759: if ((avail_end <= phys_start) || (avail_end > phys_end))
760: avail_end = phys_end;
761:
762: seg->avail_start = avail_start;
763: seg->avail_end = avail_end;
764: vm_page_load(seg_index, phys_start, phys_end, avail_start, avail_end);
765: }
766:
767: void __init
768: biosmem_setup(void)
769: {
770: struct biosmem_segment *seg;
771: unsigned int i;
772:
773: biosmem_map_show();
774:
775: for (i = 0; i < ARRAY_SIZE(biosmem_segments); i++) {
776: if (biosmem_segment_size(i) == 0)
777: break;
778:
779: seg = &biosmem_segments[i];
780: biosmem_load_segment(seg, VM_PAGE_HIGHMEM_LIMIT, seg->start, seg->end,
781: biosmem_heap_start, biosmem_heap_cur);
782: }
783: }
784:
785: static void __init
786: biosmem_free_usable_range(phys_addr_t start, phys_addr_t end)
787: {
788: struct vm_page *page;
789:
790: printf("biosmem: release to vm_page: %llx-%llx (%lluk)\n",
791: (unsigned long long)start, (unsigned long long)end,
792: (unsigned long long)((end - start) >> 10));
793:
794: while (start < end) {
795: page = vm_page_lookup_pa(start);
796: assert(page != NULL);
797: vm_page_manage(page);
798: start += PAGE_SIZE;
799: }
800: }
801:
802: static void __init
803: biosmem_free_usable_update_start(phys_addr_t *start, phys_addr_t res_start,
804: phys_addr_t res_end)
805: {
806: if ((*start >= res_start) && (*start < res_end))
807: *start = res_end;
808: }
809:
810: static phys_addr_t __init
811: biosmem_free_usable_start(phys_addr_t start)
812: {
813: const struct biosmem_segment *seg;
814: unsigned int i;
815:
816: biosmem_free_usable_update_start(&start, _kvtophys(&_start),
817: _kvtophys(&_end));
818: biosmem_free_usable_update_start(&start, biosmem_heap_start,
819: biosmem_heap_end);
820:
821: for (i = 0; i < ARRAY_SIZE(biosmem_segments); i++) {
822: seg = &biosmem_segments[i];
823: biosmem_free_usable_update_start(&start, seg->avail_start,
824: seg->avail_end);
825: }
826:
827: return start;
828: }
829:
830: static int __init
831: biosmem_free_usable_reserved(phys_addr_t addr)
832: {
833: const struct biosmem_segment *seg;
834: unsigned int i;
835:
836: if ((addr >= _kvtophys(&_start))
837: && (addr < _kvtophys(&_end)))
838: return 1;
839:
840: if ((addr >= biosmem_heap_start) && (addr < biosmem_heap_end))
841: return 1;
842:
843: for (i = 0; i < ARRAY_SIZE(biosmem_segments); i++) {
844: seg = &biosmem_segments[i];
845:
846: if ((addr >= seg->avail_start) && (addr < seg->avail_end))
847: return 1;
848: }
849:
850: return 0;
851: }
852:
853: static phys_addr_t __init
854: biosmem_free_usable_end(phys_addr_t start, phys_addr_t entry_end)
855: {
856: while (start < entry_end) {
857: if (biosmem_free_usable_reserved(start))
858: break;
859:
860: start += PAGE_SIZE;
861: }
862:
863: return start;
864: }
865:
866: static void __init
867: biosmem_free_usable_entry(phys_addr_t start, phys_addr_t end)
868: {
869: phys_addr_t entry_end;
870:
871: entry_end = end;
872:
873: for (;;) {
874: start = biosmem_free_usable_start(start);
875:
876: if (start >= entry_end)
877: return;
878:
879: end = biosmem_free_usable_end(start, entry_end);
880: biosmem_free_usable_range(start, end);
881: start = end;
882: }
883: }
884:
885: void __init
886: biosmem_free_usable(void)
887: {
888: struct biosmem_map_entry *entry;
889: uint64_t start, end;
890: unsigned int i;
891:
892: for (i = 0; i < biosmem_map_size; i++) {
893: entry = &biosmem_map[i];
894:
895: if (entry->type != BIOSMEM_TYPE_AVAILABLE)
896: continue;
897:
898: start = vm_page_round(entry->base_addr);
899:
900: if (start >= VM_PAGE_HIGHMEM_LIMIT)
901: break;
902:
903: end = vm_page_trunc(entry->base_addr + entry->length);
904:
905: if (start < BIOSMEM_BASE)
906: start = BIOSMEM_BASE;
907:
908: biosmem_free_usable_entry(start, end);
909: }
910: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.