[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



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.