|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen master] device-tree: validate hwdom bank 0 boot placement
commit af11b93e3e98235d38114ba44a6d3134aa2ba2a0
Author: Mykola Kvach <mykola_kvach@xxxxxxxx>
AuthorDate: Mon Jun 8 07:39:19 2026 +0100
Commit: Michal Orzel <michal.orzel@xxxxxxx>
CommitDate: Tue Jun 9 16:13:28 2026 +0100
device-tree: validate hwdom bank 0 boot placement
With LLC coloring enabled, the hardware domain memory is allocated by
allocate_hwdom_memory() rather than by using the fixed direct-map layout.
Commit de99f3263555 ("device-tree: Improve hwdom memory allocation for
DMA") made that allocator prefer lower host regions. The first-bank
filter, however, still only checked the old 128MB heuristic. A low region
can satisfy that heuristic but still be too small, or otherwise
unsuitable, for the hardware-domain kernel and the DTB/initrd area to fit
in bank 0 according to the Arm placement rules.
Keep the existing first-bank size policy and add an architecture-specific
candidate check. On Arm, compute the kernel load address for the
candidate bank using the same logic as kernel_zimage_place(), verify that
the kernel range is covered by that bank, and then reuse the same
DTB/initrd placement helper as place_dtb_initrd(). The FDT is generated
later, so use the hardware-domain FDT allocation size as a conservative
upper bound for the final DTB size.
Check the candidate after capping the host region by the remaining
unassigned hardware-domain memory, so the validation is performed against
the size that would actually become bank 0.
This keeps the DMA-oriented allocation policy from de99f3263555 while
preventing a too-small bank 0 from reaching place_dtb_initrd().
Make kernel_zimage_place_in_bank() return INVALID_PADDR when a
position-independent zImage cannot be placed in the supplied bank; the
real load path turns this into a panic, while the hwdom candidate check
uses it to reject the bank.
Fixes: de99f3263555 ("device-tree: Improve hwdom memory allocation for DMA")
Signed-off-by: Mykola Kvach <mykola_kvach@xxxxxxxx>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
Reviewed-by: Michal Orzel <michal.orzel@xxxxxxx>
---
xen/arch/arm/acpi/domain_build.c | 2 --
xen/arch/arm/domain_build.c | 8 +++++
xen/arch/arm/include/asm/domain_build.h | 4 +++
xen/arch/arm/include/asm/kernel.h | 10 +++++++
xen/arch/arm/kernel.c | 53 +++++++++++++++++++++++++++++++--
xen/common/device-tree/domain-build.c | 25 +++++++++++-----
xen/include/xen/fdt-kernel.h | 14 +++++++++
7 files changed, 105 insertions(+), 11 deletions(-)
diff --git a/xen/arch/arm/acpi/domain_build.c b/xen/arch/arm/acpi/domain_build.c
index 249d899c33..db16f7fa94 100644
--- a/xen/arch/arm/acpi/domain_build.c
+++ b/xen/arch/arm/acpi/domain_build.c
@@ -26,8 +26,6 @@
#undef virt_to_mfn
#define virt_to_mfn(va) _mfn(__virt_to_mfn(va))
-#define ACPI_DOM0_FDT_MIN_SIZE 4096
-
static int __init acpi_iomem_deny_access(struct domain *d)
{
acpi_status status;
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 1efddc60ef..550617f152 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -115,6 +115,14 @@ int __init parse_arch_dom0_param(const char *s, const char
*e)
(IS_ENABLED(CONFIG_STATIC_SHM) ? \
(NR_SHMEM_BANKS * (160 + 16)) : 0))
+paddr_t __init hwdom_get_fdt_alloc_size(void)
+{
+ if ( acpi_disabled )
+ return fdt_totalsize(device_tree_flattened) + DOM0_FDT_EXTRA_SIZE;
+
+ return ACPI_DOM0_FDT_MIN_SIZE;
+}
+
unsigned int __init dom0_max_vcpus(void)
{
if ( opt_dom0_max_vcpus == 0 )
diff --git a/xen/arch/arm/include/asm/domain_build.h
b/xen/arch/arm/include/asm/domain_build.h
index df8b361b3d..85cf46a958 100644
--- a/xen/arch/arm/include/asm/domain_build.h
+++ b/xen/arch/arm/include/asm/domain_build.h
@@ -19,6 +19,10 @@ int prepare_acpi(struct domain *d, struct kernel_info
*kinfo);
int add_ext_regions(unsigned long s_gfn, unsigned long e_gfn, void *data);
+#define ACPI_DOM0_FDT_MIN_SIZE 4096
+
+paddr_t hwdom_get_fdt_alloc_size(void);
+
#if defined(CONFIG_MPU) && defined(CONFIG_ARM_64)
/* Utility function to determine if an Armv8-R processor supports VMSA. */
bool has_v8r_vmsa_support(void);
diff --git a/xen/arch/arm/include/asm/kernel.h
b/xen/arch/arm/include/asm/kernel.h
index 21f4273fa1..b86c7337fe 100644
--- a/xen/arch/arm/include/asm/kernel.h
+++ b/xen/arch/arm/include/asm/kernel.h
@@ -8,12 +8,22 @@
#include <asm/domain.h>
+#include <xen/types.h>
+
+struct kernel_info;
+
struct arch_kernel_info
{
/* Enable pl011 emulation */
bool vpl011;
};
+#define arch_hwdom_first_bank_can_fit_modules \
+ arch_hwdom_first_bank_can_fit_modules
+bool arch_hwdom_first_bank_can_fit_modules(const struct kernel_info *info,
+ paddr_t bank_start,
+ paddr_t bank_size);
+
#endif /* #ifdef __ARCH_ARM_KERNEL_H__ */
/*
diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
index d1be4d8074..47229644b2 100644
--- a/xen/arch/arm/kernel.c
+++ b/xen/arch/arm/kernel.c
@@ -64,6 +64,9 @@ kernel_zimage_place_in_bank(const struct kernel_info *info,
load_end = bank_start + bank_size;
load_end = MIN(bank_start + MB(128), load_end);
+ if ( load_end - bank_start < info->image.len )
+ return INVALID_PADDR;
+
load_addr = load_end - info->image.len;
/* Align to 2MB */
load_addr &= ~(MB(2) - 1);
@@ -164,9 +167,55 @@ static void __init place_dtb_initrd(struct kernel_info
*info,
static paddr_t __init kernel_zimage_place(struct kernel_info *info)
{
const struct membanks *mem = kernel_info_get_mem(info);
+ paddr_t load_addr;
+
+ load_addr = kernel_zimage_place_in_bank(info, mem->bank[0].start,
+ mem->bank[0].size);
+ if ( load_addr == INVALID_PADDR )
+ panic("Unable to find suitable location for the kernel\n");
+
+ return load_addr;
+}
+
+bool __init arch_hwdom_first_bank_can_fit_modules(const struct kernel_info
*info,
+ paddr_t bank_start,
+ paddr_t bank_size)
+{
+ const struct boot_module *initrd = info->bd.initrd;
+ /*
+ * place_dtb_initrd() rounds the DTB and initrd placement to 2MB
boundaries;
+ * use the same granularity when checking whether the first bank can hold
+ * them.
+ */
+ const paddr_t initrd_len = ROUNDUP(initrd ? initrd->size : 0, MB(2));
+ /*
+ * The hardware domain FDT has not been generated yet. Use the allocation
+ * size as a conservative upper bound for the final DTB size.
+ */
+ const paddr_t dtb_len = ROUNDUP(hwdom_get_fdt_alloc_size(), MB(2));
+ const paddr_t rambase = bank_start;
+ const paddr_t ramsize = bank_size;
+ const paddr_t dtb_initrd_size = initrd_len + dtb_len;
+ const paddr_t ramend = rambase + ramsize;
+ paddr_t kernbase;
+ paddr_t kernend;
+ paddr_t dtb_base;
+
+ kernbase = kernel_zimage_place_in_bank(info, bank_start, bank_size);
+ if ( kernbase == INVALID_PADDR )
+ return false;
+
+ kernend = kernbase + info->image.len;
+
+ if ( (kernbase < rambase) || (kernend > ramend) )
+ return false;
+
+ if ( !first_bank_can_fit_modules(ramsize, kernbase, kernend,
+ dtb_initrd_size) )
+ return false;
- return kernel_zimage_place_in_bank(info, mem->bank[0].start,
- mem->bank[0].size);
+ return find_dtb_initrd_placement(rambase, ramend, kernbase, kernend,
+ dtb_initrd_size, &dtb_base);
}
static void __init kernel_zimage_load(struct kernel_info *info)
diff --git a/xen/common/device-tree/domain-build.c
b/xen/common/device-tree/domain-build.c
index f3ba496f1e..30a59abfa7 100644
--- a/xen/common/device-tree/domain-build.c
+++ b/xen/common/device-tree/domain-build.c
@@ -299,20 +299,31 @@ static bool __init allocate_hwdom_memory(struct
kernel_info *kinfo)
for ( i = 0; (kinfo->unassigned_mem > 0) && (i < nr_banks); i++ )
{
- paddr_t bank_size;
+ const paddr_t bank_start = hwdom_free_mem->bank[i].start;
+ paddr_t bank_size = hwdom_free_mem->bank[i].size;
+
+ /*
+ * Check the size that would actually be assigned, not just the size
+ * of the host region.
+ */
+ bank_size = min(bank_size, kinfo->unassigned_mem);
/*
* The first bank must be large enough for place_dtb_initrd() to
* fit the kernel, DTB and initrd. Skip small regions to avoid
* ending up with a tiny first bank.
*/
- if ( !mem->nr_banks && (hwdom_free_mem->bank[i].size < min_bank_size) )
- continue;
+ if ( !mem->nr_banks )
+ {
+ if ( bank_size < min_bank_size )
+ continue;
+
+ if ( !arch_hwdom_first_bank_can_fit_modules(kinfo, bank_start,
+ bank_size) )
+ continue;
+ }
- bank_size = MIN(hwdom_free_mem->bank[i].size, kinfo->unassigned_mem);
- if ( !allocate_bank_memory(kinfo,
- gaddr_to_gfn(hwdom_free_mem->bank[i].start),
- bank_size) )
+ if ( !allocate_bank_memory(kinfo, gaddr_to_gfn(bank_start), bank_size)
)
{
xfree(hwdom_free_mem);
return false;
diff --git a/xen/include/xen/fdt-kernel.h b/xen/include/xen/fdt-kernel.h
index 00c37be101..95d7a4299e 100644
--- a/xen/include/xen/fdt-kernel.h
+++ b/xen/include/xen/fdt-kernel.h
@@ -93,6 +93,20 @@ kernel_info_get_mem_const(const struct kernel_info *kinfo)
return container_of(&kinfo->mem.common, const struct membanks, common);
}
+/*
+ * Return whether the proposed hardware-domain first RAM bank can satisfy the
+ * architecture-specific kernel, DTB and initrd boot placement requirements.
+ */
+#ifndef arch_hwdom_first_bank_can_fit_modules
+static inline bool
+arch_hwdom_first_bank_can_fit_modules(const struct kernel_info *info,
+ paddr_t bank_start,
+ paddr_t bank_size)
+{
+ return true;
+}
+#endif
+
#ifndef KERNEL_INFO_SHM_MEM_INIT
#ifdef CONFIG_STATIC_SHM
--
generated by git-patchbot for /home/xen/git/xen.git#master
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |