[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v5 1/3] xen/device-tree: Let DT reserve map entries overlap reserved-memory
On 04/11/2024 13:39, Grygorii Strashko wrote: > > > Hi All, > > On 04.11.24 12:49, Michal Orzel wrote: >> >> >> On 27/09/2024 00:24, Shawn Anastasio wrote: >>> >>> >>> Commit 53dc37829c31 ("xen/arm: Add DT reserve map regions to >>> bootinfo.reserved_mem") changes the way reserve map regions are tracked, >>> and as a result broke bootfdt's ability to handle device trees in which >>> the reserve map and the `reserved-memory` node contain the same entries >>> as each other, as is the case on PPC when booted by skiboot. >>> >>> Fix this behavior by moving the reserve map check to after the DT has >>> been parsed and by explicitly allowing overlap with entries created by >>> `reserved-memory` nodes. >>> >>> Fixes: 53dc37829c31 ("xen/arm: Add DT reserve map regions to >>> bootinfo.reserved_mem") >>> Signed-off-by: Shawn Anastasio <sanastasio@xxxxxxxxxxxxxxxxxxxxx> >>> --- >>> xen/common/device-tree/bootfdt.c | 28 +++++++++++++++++++++++----- >>> xen/common/device-tree/bootinfo.c | 11 +++++++++-- >>> xen/include/xen/bootfdt.h | 3 ++- >>> 3 files changed, 34 insertions(+), 8 deletions(-) >>> >>> diff --git a/xen/common/device-tree/bootfdt.c >>> b/xen/common/device-tree/bootfdt.c >>> index 911a630e7d..2a51ee44a3 100644 >>> --- a/xen/common/device-tree/bootfdt.c >>> +++ b/xen/common/device-tree/bootfdt.c >>> @@ -177,7 +177,7 @@ static int __init device_tree_get_meminfo(const void >>> *fdt, int node, >>> { >>> device_tree_get_reg(&cell, address_cells, size_cells, &start, >>> &size); >>> if ( mem == bootinfo_get_reserved_mem() && >>> - check_reserved_regions_overlap(start, size) ) >>> + check_reserved_regions_overlap(start, size, NULL) ) >>> return -EINVAL; >>> /* Some DT may describe empty bank, ignore them */ >>> if ( !size ) >>> @@ -590,14 +590,36 @@ size_t __init boot_fdt_info(const void *fdt, paddr_t >>> paddr) >>> if ( nr_rsvd < 0 ) >>> panic("Parsing FDT memory reserve map failed (%d)\n", nr_rsvd); >>> >>> + ret = device_tree_for_each_node(fdt, 0, early_scan_node, NULL); >> This should be moved before fdt_num_mem_rsv so that the program flow makes >> sense. In your case nr_rsvd is >> not used immediately after. >> >>> + if ( ret ) >>> + panic("Early FDT parsing failed (%d)\n", ret); >>> + >>> for ( i = 0; i < nr_rsvd; i++ ) >>> { >>> + const struct membanks *overlap = NULL; >>> struct membank *bank; >>> paddr_t s, sz; >>> >>> if ( fdt_get_mem_rsv_paddr(device_tree_flattened, i, &s, &sz) < 0 >>> ) >>> continue; >>> >>> + if ( check_reserved_regions_overlap(s, sz, &overlap) ) >>> + { >>> + if ( overlap == bootinfo_get_reserved_mem() ) >>> + { >>> + /* >>> + * Some valid device trees, such as those generated by >>> OpenPOWER >>> + * skiboot firmware, expose all reserved memory regions in >>> the >>> + * FDT memory reservation block (here) AND in the >>> + * reserved-memory node which has already been parsed. >>> Thus, any >>> + * overlaps in the mem_reserved banks should be ignored. >>> + */ >>> + continue; >> I think this is incorrect. Imagine this scenario: >> /memreserve/ 0x40000000 0x40000000; >> and /reserved-memory/foo with: >> reg = <0x0 0x7FFFF000 0x0 0x1000>; >> >> You would ignore the entire region described with /memreserve/ even though >> it overlaps just the last page. >> >> The problem you're describing is about regions that match 1:1 in >> /memreserve/ and /reserved-memory/. >> Therefore I think you should check that the overlapped regions match exactly. >> > > I've also discovered an issue with Commit 53dc37829c31 ("xen/arm: Add DT > reserve map > regions to bootinfo.reserved_mem") - the bootloader adds Initrd in > FDT reserved map which then conflicts with Initrd module (ARM64). > > This patch, as is, doesn't fix an issue for me: > > (XEN) Checking for initrd in /chosen > (XEN) Initrd 0000000084000040-0000000086152ac6 > (XEN) Region: [0x00000084000040, 0x00000086152ac6) overlapping with mod[2]: > [0x00000084000040, 0x00000086152ac6) > (XEN) > (XEN) **************************************** > (XEN) Panic on CPU 0: > (XEN) FDT reserve map overlapped with membanks/modules > (XEN) **************************************** > > So I did fast try of Michal Orzel suggestion and it seems working for me. > And if it's working for PPC - may be that's it (feel free to incorporate). > Diff below. > > (XEN) Checking for initrd in /chosen > (XEN) Initrd 0000000084000040-0000000086152ac6 > (XEN) RAM: 0000000048000000 - 00000000bfffffff > (XEN) RAM: 0000000480000000 - 00000004ffffffff > (XEN) RAM: 0000000600000000 - 00000006ffffffff > (XEN) > (XEN) MODULE[0]: 0000000048080000 - 00000000481ec000 Xen > (XEN) MODULE[1]: 0000000048000000 - 000000004801e080 Device Tree > (XEN) MODULE[2]: 0000000084000040 - 0000000086152ac6 Ramdisk > (XEN) MODULE[3]: 0000000048300000 - 000000004a300000 Kernel > (XEN) MODULE[4]: 0000000048070000 - 0000000048080000 XSM > (XEN) RESVD[0]: 0000000060000000 - 000000007fffffff > (XEN) RESVD[1]: 00000000b0000000 - 00000000bfffffff > (XEN) RESVD[2]: 00000000a0000000 - 00000000afffffff > ... > (XEN) *** LOADING DOMAIN 0 *** > (XEN) Loading d0 kernel from boot module @ 0000000048300000 > (XEN) Loading ramdisk from boot module @ 0000000084000040 > (XEN) Allocating 1:1 mappings totalling 256MB for dom0: > (XEN) BANK[0] 0x00000050000000-0x00000060000000 (256MB) > ... > > > --- > diff --git a/xen/common/device-tree/bootinfo.c > b/xen/common/device-tree/bootinfo.c > index f2e6a1145b7c..10e997eeca8d 100644 > --- a/xen/common/device-tree/bootinfo.c > +++ b/xen/common/device-tree/bootinfo.c > @@ -124,6 +124,30 @@ static bool __init meminfo_overlap_check(const struct > membanks *mem, > return false; > } > > +static bool __init meminfo_is_exist(const struct membanks *mem, > + paddr_t region_start, > + paddr_t region_size) > +{ > + paddr_t bank_start = INVALID_PADDR, bank_end = 0; > + paddr_t region_end = region_start + region_size; > + unsigned int i, bank_num = mem->nr_banks; > + > + for ( i = 0; i < bank_num; i++ ) > + { > + bank_start = mem->bank[i].start; > + bank_end = bank_start + mem->bank[i].size; > + > + if ( INVALID_PADDR == bank_start || region_end <= bank_start || > + region_start >= bank_end ) > + continue; > + > + if ( region_start == bank_start && region_end == bank_end) > + return true; > + } > + > + return false; > +} > + > /* > * TODO: '*_end' could be 0 if the module/region is at the end of the > physical > * address space. This is for now not handled as it requires more rework. > @@ -154,6 +178,29 @@ static bool __init bootmodules_overlap_check(struct > bootmodules *bootmodules, > return false; > } > > +static bool __init bootmodules_is_exist(struct bootmodules *bootmodules, > + paddr_t region_start, > + paddr_t region_size) > +{ > + paddr_t mod_start = INVALID_PADDR, mod_end = 0; > + paddr_t region_end = region_start + region_size; > + unsigned int i, mod_num = bootmodules->nr_mods; > + > + for ( i = 0; i < mod_num; i++ ) > + { > + mod_start = bootmodules->module[i].start; > + mod_end = mod_start + bootmodules->module[i].size; > + > + if ( region_end <= mod_start || region_start >= mod_end ) > + continue; > + > + if (region_start == mod_start && region_end == mod_end) > + return true; > + } > + > + return false; > +} > + > void __init fw_unreserved_regions(paddr_t s, paddr_t e, > void (*cb)(paddr_t ps, paddr_t pe), > unsigned int first) > @@ -201,6 +248,37 @@ bool __init check_reserved_regions_overlap(paddr_t > region_start, > return false; > } > > +bool __init check_reserved_regions_is_exist(paddr_t region_start, > + paddr_t region_size) > +{ > + const struct membanks *mem_banks[] = { > + bootinfo_get_reserved_mem(), > +#ifdef CONFIG_ACPI > + bootinfo_get_acpi(), > +#endif > +#ifdef CONFIG_STATIC_SHM > + bootinfo_get_shmem(), > +#endif > + }; > + unsigned int i; > + > + /* > + * Check if input region is overlapping with reserved memory banks or > + * ACPI EfiACPIReclaimMemory (when ACPI feature is enabled) or static > + * shared memory banks (when static shared memory feature is enabled) > + */ > + for ( i = 0; i < ARRAY_SIZE(mem_banks); i++ ) > + if ( meminfo_is_exist(mem_banks[i], region_start, region_size) ) > + return true; > + > + /* Check if input region is overlapping with bootmodules */ > + if ( bootmodules_is_exist(&bootinfo.modules, > + region_start, region_size) ) > + return true; > + > + return false; > +} > + > struct bootmodule __init *add_boot_module(bootmodule_kind kind, > paddr_t start, paddr_t size, > bool domU) > diff --git a/xen/include/xen/bootfdt.h b/xen/include/xen/bootfdt.h > index 16fa05f38f38..b8db1335be6c 100644 > --- a/xen/include/xen/bootfdt.h > +++ b/xen/include/xen/bootfdt.h > @@ -159,6 +159,8 @@ extern struct bootinfo bootinfo; > > bool check_reserved_regions_overlap(paddr_t region_start, > paddr_t region_size); > +bool check_reserved_regions_is_exist(paddr_t region_start, > + paddr_t region_size); > > struct bootmodule *add_boot_module(bootmodule_kind kind, > paddr_t start, paddr_t size, bool domU); > > > > I don't think there is a need for introduction of that many functions. For a simple exact matching case we can opencode the logic a bit. On top of Shawn patch, the minimal version would look as follows: diff --git a/xen/common/device-tree/bootfdt.c b/xen/common/device-tree/bootfdt.c index d35b2629e5a1..759c790888f9 100644 --- a/xen/common/device-tree/bootfdt.c +++ b/xen/common/device-tree/bootfdt.c @@ -586,14 +586,14 @@ size_t __init boot_fdt_info(const void *fdt, paddr_t paddr) add_boot_module(BOOTMOD_FDT, paddr, fdt_totalsize(fdt), false); - nr_rsvd = fdt_num_mem_rsv(fdt); - if ( nr_rsvd < 0 ) - panic("Parsing FDT memory reserve map failed (%d)\n", nr_rsvd); - ret = device_tree_for_each_node(fdt, 0, early_scan_node, NULL); if ( ret ) panic("Early FDT parsing failed (%d)\n", ret); + nr_rsvd = fdt_num_mem_rsv(fdt); + if ( nr_rsvd < 0 ) + panic("Parsing FDT memory reserve map failed (%d)\n", nr_rsvd); + for ( i = 0; i < nr_rsvd; i++ ) { const struct membanks *overlap = NULL; @@ -605,19 +605,33 @@ size_t __init boot_fdt_info(const void *fdt, paddr_t paddr) if ( check_reserved_regions_overlap(s, sz, &overlap) ) { - if ( overlap == bootinfo_get_reserved_mem() ) + unsigned int j; + bool match = false; + + if ( overlap != reserved_mem ) + panic("FDT reserve map overlapped with membanks/modules\n"); + + /* + * Some valid device trees, such as those generated by OpenPOWER + * skiboot firmware, expose all reserved memory regions in the + * FDT memory reservation block (here) AND in the + * reserved-memory node which has already been parsed. Thus, any + * matching overlaps in the mem_reserved banks should be ignored. + */ + for ( j = 0; j < overlap->nr_banks; j++ ) { - /* - * Some valid device trees, such as those generated by OpenPOWER - * skiboot firmware, expose all reserved memory regions in the - * FDT memory reservation block (here) AND in the - * reserved-memory node which has already been parsed. Thus, any - * overlaps in the mem_reserved banks should be ignored. - */ - continue; + if ( (overlap->bank[j].start == s) && + (overlap->bank[j].size == sz) ) + { + match = true; + break; + } } - else - panic("FDT reserve map overlapped with membanks/modules\n"); + + if ( match ) + continue; + + panic("FDT reserve map partially overlaps with /reserved-memory\n"); } if ( reserved_mem->nr_banks < reserved_mem->max_banks ) Let's wait for Shawn test and other DT maintainers opinion. ~Michal
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |