Annotation of Gnu-Mach/i386/i386at/biosmem.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.