Applied, thanks!
Mike Kelly, le dim. 25 oct. 2026 08:03:14 +0000, a ecrit:
> Some machines have a memory map showing 'reserved' memory regions
> spanning an entire memory segment. Currently this condition terminates
> memory mapping early which prevents higher segments from being
> considered during biosmem startup. This results in a failed assertion
> later on whilst booting the vm_page tables.
> ---
> i386/i386at/biosmem.c | 24 +++------
> vm/vm_page.c | 116 +++++++++++++++++++++++-------------------
> 2 files changed, 72 insertions(+), 68 deletions(-)
>
> diff --git a/i386/i386at/biosmem.c b/i386/i386at/biosmem.c
> index ce1fe9c7..b6887eff 100644
> --- a/i386/i386at/biosmem.c
> +++ b/i386/i386at/biosmem.c
> @@ -713,10 +713,8 @@ biosmem_bootstrap_common(void)
> phys_end = VM_PAGE_DMA32_LIMIT;
> error = biosmem_map_find_avail(&phys_start, &phys_end);
>
> - if (error)
> - return;
> -
> - biosmem_set_segment(VM_PAGE_SEG_DMA32, phys_start, phys_end);
> + if (!error)
> + biosmem_set_segment(VM_PAGE_SEG_DMA32, phys_start, phys_end);
>
> phys_start = VM_PAGE_DMA32_LIMIT;
> #endif
> @@ -725,10 +723,8 @@ biosmem_bootstrap_common(void)
> phys_end = VM_PAGE_DIRECTMAP_LIMIT;
> error = biosmem_map_find_avail(&phys_start, &phys_end);
>
> - if (error)
> - return;
> -
> - biosmem_set_segment(VM_PAGE_SEG_DIRECTMAP, phys_start, phys_end);
> + if (!error)
> + biosmem_set_segment(VM_PAGE_SEG_DIRECTMAP, phys_start, phys_end);
>
> phys_start = VM_PAGE_DIRECTMAP_LIMIT;
>
> @@ -737,10 +733,8 @@ biosmem_bootstrap_common(void)
> phys_end = VM_PAGE_DMA32_LIMIT;
> error = biosmem_map_find_avail(&phys_start, &phys_end);
>
> - if (error)
> - return;
> -
> - biosmem_set_segment(VM_PAGE_SEG_DMA32, phys_start, phys_end);
> + if (!error)
> + biosmem_set_segment(VM_PAGE_SEG_DMA32, phys_start, phys_end);
>
> phys_start = VM_PAGE_DMA32_LIMIT;
> #endif
> @@ -749,10 +743,8 @@ biosmem_bootstrap_common(void)
> phys_end = VM_PAGE_HIGHMEM_LIMIT;
> error = biosmem_map_find_avail(&phys_start, &phys_end);
>
> - if (error)
> - return;
> -
> - biosmem_set_segment(VM_PAGE_SEG_HIGHMEM, phys_start, phys_end);
> + if (!error)
> + biosmem_set_segment(VM_PAGE_SEG_HIGHMEM, phys_start, phys_end);
> }
>
> #ifdef MACH_HYP
> diff --git a/vm/vm_page.c b/vm/vm_page.c
> index f6f3981d..5d733120 100644
> --- a/vm/vm_page.c
> +++ b/vm/vm_page.c
> @@ -225,6 +225,7 @@ struct vm_page_seg {
> phys_addr_t end;
> struct vm_page *pages;
> struct vm_page *pages_end;
> + unsigned int type;
> simple_lock_data_t lock;
> struct vm_page_free_list free_lists[VM_PAGE_NR_FREE_LISTS];
> unsigned long nr_free_pages;
> @@ -271,8 +272,31 @@ static int vm_page_is_ready __read_mostly;
> * possible from the direct physical mapping, DMA and DMA32 are aliases for
> * DIRECTMAP, in which case the segment table contains DIRECTMAP and HIGHMEM
> * only.
> + *
> + * All elements of 'vm_page_boot_segs' are always valid. This is the
> + * case even if the machine's physical memory address range does not
> + * cover all segment types. Moreover, some machines have a memory map
> + * in which an intermediate segment has either no memory or no
> + * 'available' memory. vm_page_boot_seg_size() can be used to assess
> + * whether a given element has 'available' memory.
> + *
> + * 'vm_page_segs' only contains elements that have 'available'
> + * memory. 'vm_page_segs_size' can therefore be lower than
> + * VM_PAGE_MAX_SEGS even if the VM_PAGE_SEG_HIGHMEM segment is
> + * present. The index position in vm_page_segs therefore has no
> + * particular significance unlike vm_page_boot_segs.
> + *
> + * It is sometimes important to select free memory with a certain
> + * 'type'. The vm_page_segs_type_to_index array defines the
> + * appropriate mapping between segment type and index into
> + * 'vm_page_segs'. There are always VM_PAGE_MAX_SEGS defined by this
> + * array.
> + *
> + * Note that vm_page.seg_index is the index into vm_page_segs which is
> + * not necessarily the same as the segment 'type'.
> */
> static struct vm_page_seg vm_page_segs[VM_PAGE_MAX_SEGS];
> +static unsigned int vm_page_segs_type_to_index[VM_PAGE_MAX_SEGS];
>
> /*
> * Bootstrap segment table.
> @@ -671,6 +695,7 @@ vm_page_seg_compute_pageout_thresholds(struct vm_page_seg
> *seg)
>
> static void __init
> vm_page_seg_init(struct vm_page_seg *seg, phys_addr_t start, phys_addr_t end,
> + unsigned int seg_index,
> struct vm_page *pages)
> {
> phys_addr_t pa;
> @@ -679,6 +704,7 @@ vm_page_seg_init(struct vm_page_seg *seg, phys_addr_t
> start, phys_addr_t end,
>
> seg->start = start;
> seg->end = end;
> + seg->type = seg_index;
> pool_size = vm_page_seg_compute_pool_size(seg);
>
> for (i = 0; i < ARRAY_SIZE(seg->cpu_pools); i++)
> @@ -1460,7 +1486,6 @@ vm_page_load(unsigned int seg_index, phys_addr_t start,
> phys_addr_t end)
> assert(vm_page_aligned(start));
> assert(vm_page_aligned(end));
> assert(start < end);
> - assert(vm_page_segs_size < ARRAY_SIZE(vm_page_boot_segs));
>
> seg = &vm_page_boot_segs[seg_index];
> seg->start = start;
> @@ -1472,8 +1497,6 @@ vm_page_load(unsigned int seg_index, phys_addr_t start,
> phys_addr_t end)
> vm_page_seg_name(seg_index),
> (unsigned long long)start, (unsigned long long)end);
> #endif
> -
> - vm_page_segs_size++;
> }
>
> void
> @@ -1529,32 +1552,7 @@ vm_page_select_alloc_seg(unsigned int selector)
> panic("vm_page: invalid selector");
> }
>
> - return MIN(vm_page_segs_size - 1, seg_index);
> -}
> -
> -static int __init
> -vm_page_boot_seg_loaded(const struct vm_page_boot_seg *seg)
> -{
> - return (seg->end != 0);
> -}
> -
> -static void __init
> -vm_page_check_boot_segs(void)
> -{
> - unsigned int i;
> - int expect_loaded;
> -
> - if (vm_page_segs_size == 0)
> - panic("vm_page: no physical memory loaded");
> -
> - for (i = 0; i < ARRAY_SIZE(vm_page_boot_segs); i++) {
> - expect_loaded = (i < vm_page_segs_size);
> -
> - if (vm_page_boot_seg_loaded(&vm_page_boot_segs[i]) == expect_loaded)
> - continue;
> -
> - panic("vm_page: invalid boot segment table");
> - }
> + return vm_page_segs_type_to_index[seg_index];
> }
>
> static phys_addr_t __init
> @@ -1576,8 +1574,8 @@ vm_page_bootalloc(size_t size)
> phys_addr_t pa;
> unsigned int i;
>
> - for (i = vm_page_select_alloc_seg(VM_PAGE_SEL_DIRECTMAP);
> - i < vm_page_segs_size;
> + for (i = VM_PAGE_SEG_DIRECTMAP;
> + i < ARRAY_SIZE(vm_page_boot_segs);
> i--) {
> seg = &vm_page_boot_segs[i];
>
> @@ -1602,8 +1600,6 @@ vm_page_setup(void)
> unsigned int i;
> phys_addr_t pa;
>
> - vm_page_check_boot_segs();
> -
> list_init(&vm_page_active_lru_list.internal);
> list_init(&vm_page_active_lru_list.external);
> list_init(&vm_page_inactive_lru_list.internal);
> @@ -1614,9 +1610,12 @@ vm_page_setup(void)
> */
> nr_pages = 0;
>
> - for (i = 0; i < vm_page_segs_size; i++)
> + for (i = 0; i < ARRAY_SIZE(vm_page_boot_segs); i++)
> nr_pages +=
> vm_page_atop(vm_page_boot_seg_size(&vm_page_boot_segs[i]));
>
> + if (nr_pages == 0)
> + panic("vm_page: no physical memory loaded");
> +
> table_size = vm_page_round(nr_pages * sizeof(struct vm_page));
> printf("vm_page: page table size: %lu entries (%luk)\n",
> (unsigned long) nr_pages,
> @@ -1629,22 +1628,34 @@ vm_page_setup(void)
> * the segments are initialized, all their pages are set allocated.
> * Pages are then released, which populates the free lists.
> */
> - for (i = 0; i < vm_page_segs_size; i++) {
> - seg = &vm_page_segs[i];
> + for (i = 0; i < ARRAY_SIZE(vm_page_boot_segs); i++) {
> boot_seg = &vm_page_boot_segs[i];
> - vm_page_seg_init(seg, boot_seg->start, boot_seg->end, table);
> - page = seg->pages + vm_page_atop(boot_seg->avail_start
> - - boot_seg->start);
> - end = seg->pages + vm_page_atop(boot_seg->avail_end
> - - boot_seg->start);
> -
> - while (page < end) {
> - page->type = VM_PT_FREE;
> - vm_page_seg_free_to_buddy(seg, page, 0);
> - page++;
> - }
>
> - table += vm_page_atop(vm_page_seg_size(seg));
> + if (vm_page_boot_seg_size(boot_seg))
> + {
> + vm_page_segs_type_to_index[i] = vm_page_segs_size;
> + seg = &vm_page_segs[vm_page_segs_size++];
> + vm_page_seg_init(seg, boot_seg->start, boot_seg->end, i, table);
> + page = seg->pages + vm_page_atop(boot_seg->avail_start
> + - boot_seg->start);
> + end = seg->pages + vm_page_atop(boot_seg->avail_end
> + - boot_seg->start);
> +
> + while (page < end) {
> + page->type = VM_PT_FREE;
> + vm_page_seg_free_to_buddy(seg, page, 0);
> + page++;
> + }
> +
> + table += vm_page_atop(vm_page_seg_size(seg));
> + }
> + else
> + {
> + vm_page_segs_type_to_index[i] =
> + (vm_page_segs_size != 0
> + ? vm_page_segs_type_to_index[vm_page_segs_size - 1]
> + : 0);
> + }
> }
>
> while (va < (unsigned long)table) {
> @@ -1827,10 +1838,10 @@ vm_page_info_all(void)
> seg = &vm_page_segs[i];
> pages = (unsigned long)(seg->pages_end - seg->pages);
> printf("vm_page: %s: pages: %lu (%luM), free: %lu (%luM)\n",
> - vm_page_seg_name(i), pages, pages >> (20 - PAGE_SHIFT),
> + vm_page_seg_name(seg->type), pages, pages >> (20 -
> PAGE_SHIFT),
> seg->nr_free_pages, seg->nr_free_pages >> (20 - PAGE_SHIFT));
> printf("vm_page: %s: min:%lu low:%lu high:%lu\n",
> - vm_page_seg_name(vm_page_seg_index(seg)),
> + vm_page_seg_name(seg->type),
> seg->min_free_pages, seg->low_free_pages,
> seg->high_free_pages);
> }
> }
> @@ -1849,7 +1860,7 @@ vm_page_boot_table_size(void)
>
> nr_pages = 0;
>
> - for (i = 0; i < vm_page_segs_size; i++) {
> + for (i = 0; i < ARRAY_SIZE(vm_page_boot_segs); i++) {
> nr_pages +=
> vm_page_atop(vm_page_boot_seg_size(&vm_page_boot_segs[i]));
> }
>
> @@ -2359,7 +2370,8 @@ void db_show_vmstat(void)
> (vm_page_segs[i].inactive_pages.internal.nr_pages +
> vm_page_segs[i].inactive_pages.external.nr_pages);
>
> - db_printf("\nSegment %s:\n", vm_page_seg_name(i));
> + db_printf("\nSegment %s:\n",
> + vm_page_seg_name(vm_page_segs[i].type));
> db_printf("%-20s %10uM\n", "size:",
> vm_page_seg_size(&vm_page_segs[i]) >> 20);
> db_printf("%-20s %10uM\n", "free:",
> --
> 2.47.3
>
>
--
Samuel
> Allez, soyez sympa ... traduisez-lui "linux"
Linux, c'est comme le miel : c'est vachement bon mais ça attire les
mouches. En plus, ça colle aux doigts et on a du mal à s'en défaire.
-+- TP in: Guide du linuxien pervers - "Barrez vous les mouches !"