--- Gnu-Mach/i386/i386at/biosmem.c 2020/09/02 04:53:39 1.1 +++ Gnu-Mach/i386/i386at/biosmem.c 2020/09/02 04:55:41 1.1.1.2 @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -29,19 +28,40 @@ #include #include +#define DEBUG 0 + #define __boot #define __bootdata #define __init #define boot_memmove memmove -#define boot_panic panic +#define boot_panic(s) panic("%s", s) #define boot_strlen strlen #define BOOT_CGAMEM phystokv(0xb8000) #define BOOT_CGACHARS (80 * 25) #define BOOT_CGACOLOR 0x7 -extern char _start, _end; +#define BIOSMEM_MAX_BOOT_DATA 64 + +/* + * Boot data descriptor. + * + * The start and end addresses must not be page-aligned, since there + * could be more than one range inside a single page. + */ +struct biosmem_boot_data { + phys_addr_t start; + phys_addr_t end; + boolean_t temporary; +}; + +/* + * Sorted array of boot data descriptors. + */ +static struct biosmem_boot_data biosmem_boot_data_array[BIOSMEM_MAX_BOOT_DATA] + __bootdata; +static unsigned int biosmem_nr_boot_data __bootdata; /* * Maximum number of entries in the BIOS memory map. @@ -71,19 +91,6 @@ struct biosmem_map_entry { }; /* - * Contiguous block of physical memory. - * - * Tha "available" range records what has been passed to the VM system as - * available inside the segment. - */ -struct biosmem_segment { - phys_addr_t start; - phys_addr_t end; - phys_addr_t avail_start; - phys_addr_t avail_end; -}; - -/* * Memory map built from the information passed by the boot loader. * * If the boot loader didn't pass a valid memory map, a simple map is built @@ -94,6 +101,14 @@ static struct biosmem_map_entry biosmem_ static unsigned int biosmem_map_size __bootdata; /* + * Contiguous block of physical memory. + */ +struct biosmem_segment { + phys_addr_t start; + phys_addr_t end; +}; + +/* * Physical segment boundaries. */ static struct biosmem_segment biosmem_segments[VM_PAGE_MAX_SEGS] __bootdata; @@ -103,11 +118,24 @@ static struct biosmem_segment biosmem_se * * This heap is located above BIOS memory. */ -static uint32_t biosmem_heap_start __bootdata; -static uint32_t biosmem_heap_cur __bootdata; -static uint32_t biosmem_heap_end __bootdata; +static phys_addr_t biosmem_heap_start __bootdata; +static phys_addr_t biosmem_heap_bottom __bootdata; +static phys_addr_t biosmem_heap_top __bootdata; +static phys_addr_t biosmem_heap_end __bootdata; + +/* + * Boot allocation policy. + * + * Top-down allocations are normally preferred to avoid unnecessarily + * filling the DMA segment. + */ +static boolean_t biosmem_heap_topdown __bootdata; -static char biosmem_panic_toobig_msg[] __bootdata +static char biosmem_panic_inval_boot_data[] __bootdata + = "biosmem: invalid boot data"; +static char biosmem_panic_too_many_boot_data[] __bootdata + = "biosmem: too many boot data ranges"; +static char biosmem_panic_too_big_msg[] __bootdata = "biosmem: too many memory map entries"; #ifndef MACH_HYP static char biosmem_panic_setup_msg[] __bootdata @@ -120,6 +148,103 @@ static char biosmem_panic_inval_msg[] __ static char biosmem_panic_nomem_msg[] __bootdata = "biosmem: unable to allocate memory"; +void __boot +biosmem_register_boot_data(phys_addr_t start, phys_addr_t end, + boolean_t temporary) +{ + unsigned int i; + + if (start >= end) { + boot_panic(biosmem_panic_inval_boot_data); + } + + if (biosmem_nr_boot_data == ARRAY_SIZE(biosmem_boot_data_array)) { + boot_panic(biosmem_panic_too_many_boot_data); + } + + for (i = 0; i < biosmem_nr_boot_data; i++) { + /* Check if the new range overlaps */ + if ((end > biosmem_boot_data_array[i].start) + && (start < biosmem_boot_data_array[i].end)) { + + /* + * If it does, check whether it's part of another range. + * For example, this applies to debugging symbols directly + * taken from the kernel image. + */ + if ((start >= biosmem_boot_data_array[i].start) + && (end <= biosmem_boot_data_array[i].end)) { + + /* + * If it's completely included, make sure that a permanent + * range remains permanent. + * + * XXX This means that if one big range is first registered + * as temporary, and a smaller range inside of it is + * registered as permanent, the bigger range becomes + * permanent. It's not easy nor useful in practice to do + * better than that. + */ + if (biosmem_boot_data_array[i].temporary != temporary) { + biosmem_boot_data_array[i].temporary = FALSE; + } + + return; + } + + boot_panic(biosmem_panic_inval_boot_data); + } + + if (end <= biosmem_boot_data_array[i].start) { + break; + } + } + + boot_memmove(&biosmem_boot_data_array[i + 1], + &biosmem_boot_data_array[i], + (biosmem_nr_boot_data - i) * sizeof(*biosmem_boot_data_array)); + + biosmem_boot_data_array[i].start = start; + biosmem_boot_data_array[i].end = end; + biosmem_boot_data_array[i].temporary = temporary; + biosmem_nr_boot_data++; +} + +static void __init +biosmem_unregister_boot_data(phys_addr_t start, phys_addr_t end) +{ + unsigned int i; + + if (start >= end) { + panic("%s", biosmem_panic_inval_boot_data); + } + + assert(biosmem_nr_boot_data != 0); + + for (i = 0; biosmem_nr_boot_data; i++) { + if ((start == biosmem_boot_data_array[i].start) + && (end == biosmem_boot_data_array[i].end)) { + break; + } + } + + if (i == biosmem_nr_boot_data) { + return; + } + +#if DEBUG + printf("biosmem: unregister boot data: %llx:%llx\n", + (unsigned long long)biosmem_boot_data_array[i].start, + (unsigned long long)biosmem_boot_data_array[i].end); +#endif /* DEBUG */ + + biosmem_nr_boot_data--; + + boot_memmove(&biosmem_boot_data_array[i], + &biosmem_boot_data_array[i + 1], + (biosmem_nr_boot_data - i) * sizeof(*biosmem_boot_data_array)); +} + #ifndef MACH_HYP static void __boot @@ -302,7 +427,7 @@ biosmem_map_adjust(void) */ if (biosmem_map_size >= ARRAY_SIZE(biosmem_map)) - boot_panic(biosmem_panic_toobig_msg); + boot_panic(biosmem_panic_too_big_msg); biosmem_map[biosmem_map_size] = tmp; biosmem_map_size++; @@ -321,6 +446,16 @@ biosmem_map_adjust(void) biosmem_map_sort(); } +/* + * Find addresses of physical memory within a given range. + * + * This function considers the memory map with the [*phys_start, *phys_end] + * range on entry, and returns the lowest address of physical memory + * in *phys_start, and the highest address of unusable memory immediately + * following physical memory in *phys_end. + * + * These addresses are normally used to establish the range of a segment. + */ static int __boot biosmem_map_find_avail(phys_addr_t *phys_start, phys_addr_t *phys_end) { @@ -382,161 +517,132 @@ biosmem_segment_size(unsigned int seg_in return biosmem_segments[seg_index].end - biosmem_segments[seg_index].start; } -#ifndef MACH_HYP - -static void __boot -biosmem_save_cmdline_sizes(struct multiboot_raw_info *mbi) +static int __boot +biosmem_find_avail_clip(phys_addr_t *avail_start, phys_addr_t *avail_end, + phys_addr_t data_start, phys_addr_t data_end) { - struct multiboot_raw_module *mod; - uint32_t i, va; + phys_addr_t orig_end; - if (mbi->flags & MULTIBOOT_LOADER_CMDLINE) { - va = phystokv(mbi->cmdline); - mbi->unused0 = boot_strlen((char *)va) + 1; - } + assert(data_start < data_end); - if (mbi->flags & MULTIBOOT_LOADER_MODULES) { - unsigned long addr; + orig_end = data_end; + data_start = vm_page_trunc(data_start); + data_end = vm_page_round(data_end); - addr = phystokv(mbi->mods_addr); + if (data_end < orig_end) { + boot_panic(biosmem_panic_inval_boot_data); + } - for (i = 0; i < mbi->mods_count; i++) { - mod = (struct multiboot_raw_module *)addr + i; - va = phystokv(mod->string); - mod->reserved = boot_strlen((char *)va) + 1; - } + if ((data_end <= *avail_start) || (data_start >= *avail_end)) { + return 0; } -} -static void __boot -biosmem_find_boot_data_update(uint32_t min, uint32_t *start, uint32_t *end, - uint32_t data_start, uint32_t data_end) -{ - if ((min <= data_start) && (data_start < *start)) { - *start = data_start; - *end = data_end; + if (data_start > *avail_start) { + *avail_end = data_start; + } else { + if (data_end >= *avail_end) { + return -1; + } + + *avail_start = data_end; } + + return 0; } /* - * Find the first boot data in the given range, and return their containing - * area (start address is returned directly, end address is returned in end). - * The following are considered boot data : - * - the kernel - * - the kernel command line - * - the module table - * - the modules - * - the modules command lines - * - the ELF section header table - * - the ELF .shstrtab, .symtab and .strtab sections + * Find available memory in the given range. + * + * The search starts at the given start address, up to the given end address. + * If a range is found, it is stored through the avail_startp and avail_endp + * pointers. * - * If no boot data was found, 0 is returned, and the end address isn't set. + * The range boundaries are page-aligned on return. */ -static uint32_t __boot -biosmem_find_boot_data(const struct multiboot_raw_info *mbi, uint32_t min, - uint32_t max, uint32_t *endp) +static int __boot +biosmem_find_avail(phys_addr_t start, phys_addr_t end, + phys_addr_t *avail_start, phys_addr_t *avail_end) { - struct multiboot_raw_module *mod; - struct elf_shdr *shdr; - uint32_t i, start, end = end; - unsigned long tmp; - - start = max; - - biosmem_find_boot_data_update(min, &start, &end, _kvtophys(&_start), - _kvtophys(&_end)); - - if ((mbi->flags & MULTIBOOT_LOADER_CMDLINE) && (mbi->cmdline != 0)) - biosmem_find_boot_data_update(min, &start, &end, mbi->cmdline, - mbi->cmdline + mbi->unused0); + phys_addr_t orig_start; + unsigned int i; + int error; - if (mbi->flags & MULTIBOOT_LOADER_MODULES) { - i = mbi->mods_count * sizeof(struct multiboot_raw_module); - biosmem_find_boot_data_update(min, &start, &end, mbi->mods_addr, - mbi->mods_addr + i); - tmp = phystokv(mbi->mods_addr); + assert(start <= end); - for (i = 0; i < mbi->mods_count; i++) { - mod = (struct multiboot_raw_module *)tmp + i; - biosmem_find_boot_data_update(min, &start, &end, mod->mod_start, - mod->mod_end); + orig_start = start; + start = vm_page_round(start); + end = vm_page_trunc(end); - if (mod->string != 0) - biosmem_find_boot_data_update(min, &start, &end, mod->string, - mod->string + mod->reserved); - } + if ((start < orig_start) || (start >= end)) { + return -1; } - if (mbi->flags & MULTIBOOT_LOADER_SHDR) { - tmp = mbi->shdr_num * mbi->shdr_size; - biosmem_find_boot_data_update(min, &start, &end, mbi->shdr_addr, - mbi->shdr_addr + tmp); - tmp = phystokv(mbi->shdr_addr); + *avail_start = start; + *avail_end = end; - for (i = 0; i < mbi->shdr_num; i++) { - shdr = (struct elf_shdr *)(tmp + (i * mbi->shdr_size)); - - if ((shdr->type != ELF_SHT_SYMTAB) - && (shdr->type != ELF_SHT_STRTAB)) - continue; + for (i = 0; i < biosmem_nr_boot_data; i++) { + error = biosmem_find_avail_clip(avail_start, avail_end, + biosmem_boot_data_array[i].start, + biosmem_boot_data_array[i].end); - biosmem_find_boot_data_update(min, &start, &end, shdr->addr, - shdr->addr + shdr->size); + if (error) { + return -1; } } - if (start == max) - return 0; - - *endp = end; - return start; + return 0; } +#ifndef MACH_HYP + static void __boot -biosmem_setup_allocator(struct multiboot_raw_info *mbi) +biosmem_setup_allocator(const struct multiboot_raw_info *mbi) { - uint32_t heap_start, heap_end, max_heap_start, max_heap_end; - uint32_t mem_end, next; + phys_addr_t heap_start, heap_end, max_heap_start, max_heap_end; + phys_addr_t start, end; + int error; /* * Find some memory for the heap. Look for the largest unused area in * upper memory, carefully avoiding all boot data. */ - mem_end = vm_page_trunc((mbi->mem_upper + 1024) << 10); + end = vm_page_trunc((mbi->mem_upper + 1024) << 10); #ifndef __LP64__ - if (mem_end > VM_PAGE_DIRECTMAP_LIMIT) - mem_end = VM_PAGE_DIRECTMAP_LIMIT; + if (end > VM_PAGE_DIRECTMAP_LIMIT) + end = VM_PAGE_DIRECTMAP_LIMIT; #endif /* __LP64__ */ max_heap_start = 0; max_heap_end = 0; - next = BIOSMEM_END; + start = BIOSMEM_END; - do { - heap_start = next; - heap_end = biosmem_find_boot_data(mbi, heap_start, mem_end, &next); - - if (heap_end == 0) { - heap_end = mem_end; - next = 0; + for (;;) { + error = biosmem_find_avail(start, end, &heap_start, &heap_end); + + if (error) { + break; } if ((heap_end - heap_start) > (max_heap_end - max_heap_start)) { max_heap_start = heap_start; max_heap_end = heap_end; } - } while (next != 0); - max_heap_start = vm_page_round(max_heap_start); - max_heap_end = vm_page_trunc(max_heap_end); + start = heap_end; + } if (max_heap_start >= max_heap_end) boot_panic(biosmem_panic_setup_msg); biosmem_heap_start = max_heap_start; biosmem_heap_end = max_heap_end; - biosmem_heap_cur = biosmem_heap_end; + biosmem_heap_bottom = biosmem_heap_start; + biosmem_heap_top = biosmem_heap_end; + biosmem_heap_topdown = TRUE; + + /* Prevent biosmem_free_usable() from releasing the heap */ + biosmem_register_boot_data(biosmem_heap_start, biosmem_heap_end, FALSE); } #endif /* MACH_HYP */ @@ -544,7 +650,7 @@ biosmem_setup_allocator(struct multiboot static void __boot biosmem_bootstrap_common(void) { - phys_addr_t phys_start, phys_end, last_addr; + phys_addr_t phys_start, phys_end; int error; biosmem_map_adjust(); @@ -557,7 +663,6 @@ biosmem_bootstrap_common(void) boot_panic(biosmem_panic_noseg_msg); biosmem_set_segment(VM_PAGE_SEG_DMA, phys_start, phys_end); - last_addr = phys_end; phys_start = VM_PAGE_DMA_LIMIT; #ifdef VM_PAGE_DMA32_LIMIT @@ -565,10 +670,9 @@ biosmem_bootstrap_common(void) error = biosmem_map_find_avail(&phys_start, &phys_end); if (error) - goto out; + return; biosmem_set_segment(VM_PAGE_SEG_DMA32, phys_start, phys_end); - last_addr = phys_end; phys_start = VM_PAGE_DMA32_LIMIT; #endif /* VM_PAGE_DMA32_LIMIT */ @@ -576,23 +680,18 @@ biosmem_bootstrap_common(void) error = biosmem_map_find_avail(&phys_start, &phys_end); if (error) - goto out; + return; biosmem_set_segment(VM_PAGE_SEG_DIRECTMAP, phys_start, phys_end); - last_addr = phys_end; phys_start = VM_PAGE_DIRECTMAP_LIMIT; phys_end = VM_PAGE_HIGHMEM_LIMIT; error = biosmem_map_find_avail(&phys_start, &phys_end); if (error) - goto out; + return; biosmem_set_segment(VM_PAGE_SEG_HIGHMEM, phys_start, phys_end); - -out: - /* XXX phys_last_addr must be part of the direct physical mapping */ - phys_last_addr = last_addr; } #ifdef MACH_HYP @@ -616,26 +715,34 @@ biosmem_xen_bootstrap(void) biosmem_heap_end = boot_info.nr_pages << PAGE_SHIFT; #ifndef __LP64__ - /* TODO Check that this actually makes sense */ if (biosmem_heap_end > VM_PAGE_DIRECTMAP_LIMIT) biosmem_heap_end = VM_PAGE_DIRECTMAP_LIMIT; #endif /* __LP64__ */ + biosmem_heap_bottom = biosmem_heap_start; + biosmem_heap_top = biosmem_heap_end; + /* - * XXX Allocation on Xen must be bottom-up : + * XXX Allocation on Xen are initially bottom-up : * At the "start of day", only 512k are available after the boot * data. The pmap module then creates a 4g mapping so all physical * memory is available, but it uses this allocator to do so. * Therefore, it must return pages from this small 512k regions * first. */ - biosmem_heap_cur = biosmem_heap_start; + biosmem_heap_topdown = FALSE; + + /* + * Prevent biosmem_free_usable() from releasing the Xen boot information + * and the heap. + */ + biosmem_register_boot_data(0, biosmem_heap_end, FALSE); } #else /* MACH_HYP */ void __boot -biosmem_bootstrap(struct multiboot_raw_info *mbi) +biosmem_bootstrap(const struct multiboot_raw_info *mbi) { if (mbi->flags & MULTIBOOT_LOADER_MMAP) biosmem_map_build(mbi); @@ -643,12 +750,6 @@ biosmem_bootstrap(struct multiboot_raw_i biosmem_map_build_simple(mbi); biosmem_bootstrap_common(); - - /* - * The kernel and modules command lines will be memory mapped later - * during initialization. Their respective sizes must be saved. - */ - biosmem_save_cmdline_sizes(mbi); biosmem_setup_allocator(mbi); } @@ -659,34 +760,37 @@ biosmem_bootalloc(unsigned int nr_pages) { unsigned long addr, size; - assert(!vm_page_ready()); - size = vm_page_ptoa(nr_pages); if (size == 0) boot_panic(biosmem_panic_inval_msg); -#ifdef MACH_HYP - addr = biosmem_heap_cur; -#else /* MACH_HYP */ - /* Top-down allocation to avoid unnecessarily filling DMA segments */ - addr = biosmem_heap_cur - size; -#endif /* MACH_HYP */ + if (biosmem_heap_topdown) { + addr = biosmem_heap_top - size; - if ((addr < biosmem_heap_start) || (addr > biosmem_heap_cur)) - boot_panic(biosmem_panic_nomem_msg); + if ((addr < biosmem_heap_start) || (addr > biosmem_heap_top)) { + boot_panic(biosmem_panic_nomem_msg); + } -#ifdef MACH_HYP - biosmem_heap_cur += size; -#else /* MACH_HYP */ - biosmem_heap_cur = addr; -#endif /* MACH_HYP */ + biosmem_heap_top = addr; + } else { + unsigned long end; + + addr = biosmem_heap_bottom; + end = addr + size; + + if ((end > biosmem_heap_end) || (end < biosmem_heap_bottom)) { + boot_panic(biosmem_panic_nomem_msg); + } + + biosmem_heap_bottom = end; + } return addr; } phys_addr_t __boot -biosmem_directmap_size(void) +biosmem_directmap_end(void) { if (biosmem_segment_size(VM_PAGE_SEG_DIRECTMAP) != 0) return biosmem_segment_end(VM_PAGE_SEG_DIRECTMAP); @@ -729,16 +833,21 @@ biosmem_map_show(void) entry->base_addr + entry->length, biosmem_type_desc(entry->type)); - printf("biosmem: heap: %x-%x\n", biosmem_heap_start, biosmem_heap_end); +#if DEBUG + printf("biosmem: heap: %llx:%llx\n", + (unsigned long long)biosmem_heap_start, + (unsigned long long)biosmem_heap_end); +#endif } static void __init -biosmem_load_segment(struct biosmem_segment *seg, uint64_t max_phys_end, - phys_addr_t phys_start, phys_addr_t phys_end, - phys_addr_t avail_start, phys_addr_t avail_end) +biosmem_load_segment(struct biosmem_segment *seg, uint64_t max_phys_end) { + phys_addr_t phys_start, phys_end, avail_start, avail_end; unsigned int seg_index; + phys_start = seg->start; + phys_end = seg->end; seg_index = seg - biosmem_segments; if (phys_end > max_phys_end) { @@ -753,15 +862,28 @@ biosmem_load_segment(struct biosmem_segm phys_end = max_phys_end; } - if ((avail_start < phys_start) || (avail_start >= phys_end)) - avail_start = phys_start; + vm_page_load(seg_index, phys_start, phys_end); - if ((avail_end <= phys_start) || (avail_end > phys_end)) - avail_end = phys_end; + /* + * Clip the remaining available heap to fit it into the loaded + * segment if possible. + */ - seg->avail_start = avail_start; - seg->avail_end = avail_end; - vm_page_load(seg_index, phys_start, phys_end, avail_start, avail_end); + if ((biosmem_heap_top > phys_start) && (biosmem_heap_bottom < phys_end)) { + if (biosmem_heap_bottom >= phys_start) { + avail_start = biosmem_heap_bottom; + } else { + avail_start = phys_start; + } + + if (biosmem_heap_top <= phys_end) { + avail_end = biosmem_heap_top; + } else { + avail_end = phys_end; + } + + vm_page_load_heap(seg_index, avail_start, avail_end); + } } void __init @@ -777,8 +899,25 @@ biosmem_setup(void) break; seg = &biosmem_segments[i]; - biosmem_load_segment(seg, VM_PAGE_HIGHMEM_LIMIT, seg->start, seg->end, - biosmem_heap_start, biosmem_heap_cur); + biosmem_load_segment(seg, VM_PAGE_HIGHMEM_LIMIT); + } +} + +static void __init +biosmem_unregister_temporary_boot_data(void) +{ + struct biosmem_boot_data *data; + unsigned int i; + + for (i = 0; i < biosmem_nr_boot_data; i++) { + data = &biosmem_boot_data_array[i]; + + if (!data->temporary) { + continue; + } + + biosmem_unregister_boot_data(data->start, data->end); + i = (unsigned int)-1; } } @@ -787,9 +926,11 @@ biosmem_free_usable_range(phys_addr_t st { struct vm_page *page; - printf("biosmem: release to vm_page: %llx-%llx (%lluk)\n", +#if DEBUG + printf("biosmem: release to vm_page: %llx:%llx (%lluk)\n", (unsigned long long)start, (unsigned long long)end, (unsigned long long)((end - start) >> 10)); +#endif while (start < end) { page = vm_page_lookup_pa(start); @@ -800,85 +941,20 @@ biosmem_free_usable_range(phys_addr_t st } static void __init -biosmem_free_usable_update_start(phys_addr_t *start, phys_addr_t res_start, - phys_addr_t res_end) -{ - if ((*start >= res_start) && (*start < res_end)) - *start = res_end; -} - -static phys_addr_t __init -biosmem_free_usable_start(phys_addr_t start) -{ - const struct biosmem_segment *seg; - unsigned int i; - - biosmem_free_usable_update_start(&start, _kvtophys(&_start), - _kvtophys(&_end)); - biosmem_free_usable_update_start(&start, biosmem_heap_start, - biosmem_heap_end); - - for (i = 0; i < ARRAY_SIZE(biosmem_segments); i++) { - seg = &biosmem_segments[i]; - biosmem_free_usable_update_start(&start, seg->avail_start, - seg->avail_end); - } - - return start; -} - -static int __init -biosmem_free_usable_reserved(phys_addr_t addr) -{ - const struct biosmem_segment *seg; - unsigned int i; - - if ((addr >= _kvtophys(&_start)) - && (addr < _kvtophys(&_end))) - return 1; - - if ((addr >= biosmem_heap_start) && (addr < biosmem_heap_end)) - return 1; - - for (i = 0; i < ARRAY_SIZE(biosmem_segments); i++) { - seg = &biosmem_segments[i]; - - if ((addr >= seg->avail_start) && (addr < seg->avail_end)) - return 1; - } - - return 0; -} - -static phys_addr_t __init -biosmem_free_usable_end(phys_addr_t start, phys_addr_t entry_end) -{ - while (start < entry_end) { - if (biosmem_free_usable_reserved(start)) - break; - - start += PAGE_SIZE; - } - - return start; -} - -static void __init biosmem_free_usable_entry(phys_addr_t start, phys_addr_t end) { - phys_addr_t entry_end; - - entry_end = end; + phys_addr_t avail_start, avail_end; + int error; for (;;) { - start = biosmem_free_usable_start(start); + error = biosmem_find_avail(start, end, &avail_start, &avail_end); - if (start >= entry_end) - return; + if (error) { + break; + } - end = biosmem_free_usable_end(start, entry_end); - biosmem_free_usable_range(start, end); - start = end; + biosmem_free_usable_range(avail_start, avail_end); + start = avail_end; } } @@ -889,6 +965,8 @@ biosmem_free_usable(void) uint64_t start, end; unsigned int i; + biosmem_unregister_temporary_boot_data(); + for (i = 0; i < biosmem_map_size; i++) { entry = &biosmem_map[i]; @@ -902,9 +980,17 @@ biosmem_free_usable(void) end = vm_page_trunc(entry->base_addr + entry->length); + if (end > VM_PAGE_HIGHMEM_LIMIT) { + end = VM_PAGE_HIGHMEM_LIMIT; + } + if (start < BIOSMEM_BASE) start = BIOSMEM_BASE; + if (start >= end) { + continue; + } + biosmem_free_usable_entry(start, end); } }