Annotation of Gnu-Mach/i386/i386at/biosmem.c, revision 1.1.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.