mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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. Commitde99f32635("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 fromde99f32635while 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:de99f32635("device-tree: Improve hwdom memory allocation for DMA") Signed-off-by: Mykola Kvach <mykola_kvach@epam.com> Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> Reviewed-by: Michal Orzel <michal.orzel@amd.com>
This commit is contained in:
1 parent
0656627b89
commit
af11b93e3e
7 files changed
+102
-8
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
/*
|
||||
|
||||
+50
-1
@@ -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;
|
||||
|
||||
return kernel_zimage_place_in_bank(info, mem->bank[0].start,
|
||||
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 find_dtb_initrd_placement(rambase, ramend, kernbase, kernend,
|
||||
dtb_initrd_size, &dtb_base);
|
||||
}
|
||||
|
||||
static void __init kernel_zimage_load(struct kernel_info *info)
|
||||
|
||||
@@ -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) )
|
||||
if ( !mem->nr_banks )
|
||||
{
|
||||
if ( bank_size < min_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),
|
||||
if ( !arch_hwdom_first_bank_can_fit_modules(kinfo, bank_start,
|
||||
bank_size) )
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !allocate_bank_memory(kinfo, gaddr_to_gfn(bank_start), bank_size) )
|
||||
{
|
||||
xfree(hwdom_free_mem);
|
||||
return false;
|
||||
|
||||
@@ -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
|
||||
|
||||