mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen/device-tree: Allow region overlapping with /memreserve/ ranges
There are some cases where the device tree exposes a memory range
in both /memreserve/ and reserved-memory node, in this case the
current code will stop Xen to boot since it will find that the
latter range is clashing with the already recorded /memreserve/
ranges.
Furthermore, u-boot lists boot modules ranges, such as ramdisk,
in the /memreserve/ part and even in this case this will prevent
Xen to boot since it will see that the module memory range that
it is going to add in 'add_boot_module' clashes with a /memreserve/
range.
When Xen populate the data structure that tracks the memory ranges,
it also adds a memory type described in 'enum membank_type', so
in order to fix this behavior, allow overlapping with the /memreserve/
ranges in the 'check_reserved_regions_overlap' function when a flag
is set.
In order to implement this solution, there is a distinction between
the 'struct membanks *' handled by meminfo_overlap_check(...) that
needs to be done, because the static shared memory banks doesn't have
a usable bank[].type field and so it can't be accessed, hence now
the 'struct membanks_hdr' have a 'enum region_type type' field in order
to be able to identify static shared memory banks in meminfo_overlap_check(...).
While there, set a type for the memory recorded using meminfo_add_bank()
from efi-boot.h.
Fixes: 53dc37829c ("xen/arm: Add DT reserve map regions to bootinfo.reserved_mem")
Reported-by: Shawn Anastasio <sanastasio@raptorengineering.com>
Reported-by: Grygorii Strashko <grygorii_strashko@epam.com>
Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Tested-by: Grygorii Strashko <grygorii_strashko@epam.com>
Reviewed-by: Julien Grall <jgrall@amazon.com>
This commit is contained in:
1 parent
4a06cc7178
commit
a14593e399
5 files changed
+57
-16
No files matched your search
@@ -167,13 +167,14 @@ static bool __init meminfo_add_bank(struct membanks *mem,
|
||||
if ( mem->nr_banks >= mem->max_banks )
|
||||
return false;
|
||||
#ifdef CONFIG_ACPI
|
||||
if ( check_reserved_regions_overlap(start, size) )
|
||||
if ( check_reserved_regions_overlap(start, size, false) )
|
||||
return false;
|
||||
#endif
|
||||
|
||||
bank = &mem->bank[mem->nr_banks];
|
||||
bank->start = start;
|
||||
bank->size = size;
|
||||
bank->type = MEMBANK_DEFAULT;
|
||||
|
||||
mem->nr_banks++;
|
||||
|
||||
|
||||
@@ -696,7 +696,7 @@ int __init process_shm_node(const void *fdt, int node, uint32_t address_cells,
|
||||
if (i < mem->max_banks)
|
||||
{
|
||||
if ( (paddr != INVALID_PADDR) &&
|
||||
check_reserved_regions_overlap(paddr, size) )
|
||||
check_reserved_regions_overlap(paddr, size, false) )
|
||||
return -EINVAL;
|
||||
|
||||
/* Static shared memory shall be reserved from any other use. */
|
||||
|
||||
@@ -176,8 +176,15 @@ static int __init device_tree_get_meminfo(const void *fdt, int node,
|
||||
for ( i = 0; i < banks && mem->nr_banks < mem->max_banks; i++ )
|
||||
{
|
||||
device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
|
||||
/*
|
||||
* Some valid device trees, such as those generated by OpenPOWER
|
||||
* skiboot firmware, expose all reserved memory regions in the
|
||||
* FDT memory reservation block AND in the reserved-memory node which
|
||||
* has already been parsed. Thus, any matching overlaps in the
|
||||
* reserved_mem banks should be ignored.
|
||||
*/
|
||||
if ( mem == bootinfo_get_reserved_mem() &&
|
||||
check_reserved_regions_overlap(start, size) )
|
||||
check_reserved_regions_overlap(start, size, true) )
|
||||
return -EINVAL;
|
||||
/* Some DT may describe empty bank, ignore them */
|
||||
if ( !size )
|
||||
|
||||
@@ -101,7 +101,8 @@ static void __init dt_unreserved_regions(paddr_t s, paddr_t e,
|
||||
*/
|
||||
static bool __init meminfo_overlap_check(const struct membanks *mem,
|
||||
paddr_t region_start,
|
||||
paddr_t region_size)
|
||||
paddr_t region_size,
|
||||
bool allow_memreserve_overlap)
|
||||
{
|
||||
paddr_t bank_start = INVALID_PADDR, bank_end = 0;
|
||||
paddr_t region_end = region_start + region_size;
|
||||
@@ -115,12 +116,23 @@ static bool __init meminfo_overlap_check(const struct membanks *mem,
|
||||
if ( INVALID_PADDR == bank_start || region_end <= bank_start ||
|
||||
region_start >= bank_end )
|
||||
continue;
|
||||
else
|
||||
{
|
||||
printk("Region: [%#"PRIpaddr", %#"PRIpaddr") overlapping with bank[%u]: [%#"PRIpaddr", %#"PRIpaddr")\n",
|
||||
region_start, region_end, i, bank_start, bank_end);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If allow_memreserve_overlap is set, this check allows a region to be
|
||||
* included in a MEMBANK_FDT_RESVMEM bank, but struct membanks *mem of
|
||||
* type STATIC_SHARED_MEMORY don't set the bank[].type field because
|
||||
* that is declared in a union with a field that is instead used,
|
||||
* in any case this restriction is ok since STATIC_SHARED_MEMORY banks
|
||||
* are not meant to clash with FDT /memreserve/ ranges.
|
||||
*/
|
||||
if ( allow_memreserve_overlap && mem->type != STATIC_SHARED_MEMORY &&
|
||||
region_start >= bank_start && region_end <= bank_end &&
|
||||
mem->bank[i].type == MEMBANK_FDT_RESVMEM )
|
||||
continue;
|
||||
|
||||
printk("Region: [%#"PRIpaddr", %#"PRIpaddr") overlapping with bank[%u]: [%#"PRIpaddr", %#"PRIpaddr")\n",
|
||||
region_start, region_end, i, bank_start, bank_end);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -173,7 +185,8 @@ void __init fw_unreserved_regions(paddr_t s, paddr_t e,
|
||||
* existing reserved memory regions, otherwise false.
|
||||
*/
|
||||
bool __init check_reserved_regions_overlap(paddr_t region_start,
|
||||
paddr_t region_size)
|
||||
paddr_t region_size,
|
||||
bool allow_memreserve_overlap)
|
||||
{
|
||||
const struct membanks *mem_banks[] = {
|
||||
bootinfo_get_reserved_mem(),
|
||||
@@ -192,7 +205,8 @@ bool __init check_reserved_regions_overlap(paddr_t region_start,
|
||||
* shared memory banks (when static shared memory feature is enabled)
|
||||
*/
|
||||
for ( i = 0; i < ARRAY_SIZE(mem_banks); i++ )
|
||||
if ( meminfo_overlap_check(mem_banks[i], region_start, region_size) )
|
||||
if ( meminfo_overlap_check(mem_banks[i], region_start, region_size,
|
||||
allow_memreserve_overlap) )
|
||||
return true;
|
||||
|
||||
/* Check if input region is overlapping with bootmodules */
|
||||
@@ -218,7 +232,12 @@ struct bootmodule __init *add_boot_module(bootmodule_kind kind,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( check_reserved_regions_overlap(start, size) )
|
||||
/*
|
||||
* u-boot adds boot module such as ramdisk to the /memreserve/, since these
|
||||
* ranges are saved in reserved_mem at this stage, allow an eventual exact
|
||||
* match with MEMBANK_FDT_RESVMEM banks.
|
||||
*/
|
||||
if ( check_reserved_regions_overlap(start, size, true) )
|
||||
return NULL;
|
||||
|
||||
for ( i = 0 ; i < mods->nr_mods ; i++ )
|
||||
|
||||
@@ -48,6 +48,12 @@ enum membank_type {
|
||||
MEMBANK_FDT_RESVMEM,
|
||||
};
|
||||
|
||||
enum region_type {
|
||||
MEMORY,
|
||||
RESERVED_MEMORY,
|
||||
STATIC_SHARED_MEMORY
|
||||
};
|
||||
|
||||
/* Indicates the maximum number of characters(\0 included) for shm_id */
|
||||
#define MAX_SHM_ID_LENGTH 16
|
||||
|
||||
@@ -71,6 +77,7 @@ struct membanks {
|
||||
__struct_group(membanks_hdr, common, ,
|
||||
unsigned int nr_banks;
|
||||
unsigned int max_banks;
|
||||
enum region_type type;
|
||||
);
|
||||
struct membank bank[];
|
||||
};
|
||||
@@ -136,13 +143,17 @@ struct bootinfo {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
#define BOOTINFO_ACPI_INIT .acpi.common.max_banks = NR_MEM_BANKS,
|
||||
#define BOOTINFO_ACPI_INIT \
|
||||
.acpi.common.max_banks = NR_MEM_BANKS, \
|
||||
.acpi.common.type = MEMORY
|
||||
#else
|
||||
#define BOOTINFO_ACPI_INIT
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STATIC_SHM
|
||||
#define BOOTINFO_SHMEM_INIT .shmem.common.max_banks = NR_SHMEM_BANKS,
|
||||
#define BOOTINFO_SHMEM_INIT \
|
||||
.shmem.common.max_banks = NR_SHMEM_BANKS, \
|
||||
.shmem.common.type = STATIC_SHARED_MEMORY
|
||||
#else
|
||||
#define BOOTINFO_SHMEM_INIT
|
||||
#endif
|
||||
@@ -150,7 +161,9 @@ struct bootinfo {
|
||||
#define BOOTINFO_INIT \
|
||||
{ \
|
||||
.mem.common.max_banks = NR_MEM_BANKS, \
|
||||
.mem.common.type = MEMORY, \
|
||||
.reserved_mem.common.max_banks = NR_MEM_BANKS, \
|
||||
.reserved_mem.common.type = RESERVED_MEMORY, \
|
||||
BOOTINFO_ACPI_INIT \
|
||||
BOOTINFO_SHMEM_INIT \
|
||||
}
|
||||
@@ -158,7 +171,8 @@ struct bootinfo {
|
||||
extern struct bootinfo bootinfo;
|
||||
|
||||
bool check_reserved_regions_overlap(paddr_t region_start,
|
||||
paddr_t region_size);
|
||||
paddr_t region_size,
|
||||
bool allow_memreserve_overlap);
|
||||
|
||||
struct bootmodule *add_boot_module(bootmodule_kind kind,
|
||||
paddr_t start, paddr_t size, bool domU);
|
||||
|
||||