From nobody Fri Oct 31 23:24:45 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass header.i=dpsmith@apertussolutions.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=apertussolutions.com) ARC-Seal: i=2; a=rsa-sha256; t=1745101293; cv=pass; d=zohomail.com; s=zohoarc; b=Z06hrrcZd4qZKpmqDnaqckuk8iAcerDnzRnRlbaV2lNBv7N0VhCF6d4UuRly6VABz1h8v5A4iivCsbRLyhUdmxOXAFC2TVPrELBQxHNwRXJM9IzEdhzYuKzzRCEr8CgFLC/I68ww1ntKvRHl493TGwozMfJwijGmJHdbYiGJSJ8= ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1745101293; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=xoJWXkXpmA/7bILpNXgjvSfpxAXFPtgVddP2jhGbb9Y=; b=Y7WRIkS4I5hPUJYwDAUP3/1+tV5fT5qJVho5mB2Qpjph3AAF5Al7BhvwmNWqfAdvOip8EyKoVVqRbXUPUOoMC9XVyLWUu137cbftWmBmOvPQRJPEc6m4XT4nlhIxawlTzqvrhN579Szr0FSM7LuRxIdZVVOCo6eroVoD1EU0zTc= ARC-Authentication-Results: i=2; mx.zohomail.com; dkim=pass header.i=dpsmith@apertussolutions.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; arc=pass (i=1 dmarc=pass fromdomain=apertussolutions.com) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1745101293087402.84517952236; Sat, 19 Apr 2025 15:21:33 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.960235.1352308 (Exim 4.92) (envelope-from ) id 1u6GYo-0003JX-MG; Sat, 19 Apr 2025 22:21:18 +0000 Received: by outflank-mailman (output) from mailman id 960235.1352308; Sat, 19 Apr 2025 22:21:18 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u6GYo-0003Im-CJ; Sat, 19 Apr 2025 22:21:18 +0000 Received: by outflank-mailman (input) for mailman id 960235; Sat, 19 Apr 2025 22:21:17 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1u6GP0-0004yY-0f for xen-devel@lists.xenproject.org; Sat, 19 Apr 2025 22:11:10 +0000 Received: from sender4-of-o50.zoho.com (sender4-of-o50.zoho.com [136.143.188.50]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 2ef04524-1d6b-11f0-9eb0-5ba50f476ded; Sun, 20 Apr 2025 00:11:04 +0200 (CEST) Received: by mx.zohomail.com with SMTPS id 1745100546983292.67406814920184; Sat, 19 Apr 2025 15:09:06 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 2ef04524-1d6b-11f0-9eb0-5ba50f476ded ARC-Seal: i=1; a=rsa-sha256; t=1745100550; cv=none; d=zohomail.com; s=zohoarc; b=Vx7LmSizaQI8aTsjW/xcqDxUX7t05aGQcRdNG12cItMoDos1g/aYT/dOSgq9wRpLPDzmQ+D9FDOWyQVJhZQrg9IqxuVyMrMiXpDhsP/ztvwf/27PJqc9kvnEujsff4uM0Aa6wtbDzncEi+jsv7KX3psTUmhy7M2+qKIjoQGrnro= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1745100550; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To; bh=xoJWXkXpmA/7bILpNXgjvSfpxAXFPtgVddP2jhGbb9Y=; b=FM1a+nuOcoazbxGLbwEZv/wYDNIuVSPWlh0FAYGBpKftZO8mKeHaFrGan65R4Ma49VKjlicWcIpKovrTUqTwj/tVVwqx15xN8Ctuv6gUIij7SJ65JNMSCMhsH/npm/2DONYuH0B+7BBzwoffttGCZtNjM2HkD1yekeV56v18RZw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=apertussolutions.com; spf=pass smtp.mailfrom=dpsmith@apertussolutions.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1745100550; s=zoho; d=apertussolutions.com; i=dpsmith@apertussolutions.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-Id:Message-Id:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Reply-To; bh=xoJWXkXpmA/7bILpNXgjvSfpxAXFPtgVddP2jhGbb9Y=; b=lOLk6IS7DcWYwCkOVdF1iFNpeszEdsGVHzIftxCSUCBmGBkVu57dQmH9Nt6Z2CcP 8quJhnNdzC8tcJTYYUI80bMdXRjVhVOFsqo8dqmll/LGyA5pTplbNVgt+zCMsihDiUW GXaa0EnrtOLcqe1HpMJDw7L1+ftLJdW8TGHq3cD4= From: "Daniel P. Smith" To: xen-devel@lists.xenproject.org Cc: "Daniel P. Smith" , jason.andryuk@amd.com, stefano.stabellini@amd.com, agarciav@amd.com, Jan Beulich , Andrew Cooper , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Subject: [RFC 21/38] x86/hyperlaunch: move remaining pvh dom0 construction Date: Sat, 19 Apr 2025 18:08:03 -0400 Message-Id: <20250419220820.4234-22-dpsmith@apertussolutions.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20250419220820.4234-1-dpsmith@apertussolutions.com> References: <20250419220820.4234-1-dpsmith@apertussolutions.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMailClient: External X-ZohoMail-DKIM: pass (identity dpsmith@apertussolutions.com) X-ZM-MESSAGEID: 1745101295218019000 Content-Type: text/plain; charset="utf-8" Move pvh_load_kernel() and its helper functions to the domain builder. With this move, it is now possible to move the remaining logic of dom0_construct_pvh() to the domain builder. With all the logic moved, the function can be dropped. Signed-off-by: Daniel P. Smith --- xen/arch/x86/hvm/dom0_build.c | 365 -------------------------- xen/arch/x86/hvm/dom_build.c | 362 ++++++++++++++++++++++++- xen/arch/x86/include/asm/dom0_build.h | 1 - 3 files changed, 361 insertions(+), 367 deletions(-) diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c index 73ce33fb17f1..23b46ef86c9f 100644 --- a/xen/arch/x86/hvm/dom0_build.c +++ b/xen/arch/x86/hvm/dom0_build.c @@ -478,335 +478,6 @@ int __init dom0_pvh_populate_p2m(struct domain *d) #undef MB1_PAGES } =20 -static paddr_t __init find_memory( - const struct domain *d, const struct elf_binary *elf, size_t size) -{ - paddr_t kernel_start =3D (paddr_t)elf->dest_base & PAGE_MASK; - paddr_t kernel_end =3D ROUNDUP((paddr_t)elf->dest_base + elf->dest_siz= e, - PAGE_SIZE); - unsigned int i; - - /* - * The memory map is sorted and all RAM regions starts and sizes are - * aligned to page boundaries. - */ - for ( i =3D 0; i < d->arch.nr_e820; i++ ) - { - paddr_t start, end =3D d->arch.e820[i].addr + d->arch.e820[i].size; - - /* Don't use memory below 1MB, as it could overwrite BDA/EBDA/IBFT= . */ - if ( end <=3D MB(1) || d->arch.e820[i].type !=3D E820_RAM ) - continue; - - start =3D MAX(ROUNDUP(d->arch.e820[i].addr, PAGE_SIZE), MB(1)); - - ASSERT(IS_ALIGNED(start, PAGE_SIZE) && IS_ALIGNED(end, PAGE_SIZE)); - - /* - * NB: Even better would be to use rangesets to determine a suitab= le - * range, in particular in case a kernel requests multiple heavily - * discontiguous regions (which right now we fold all into one big - * region). - */ - if ( end <=3D kernel_start || start >=3D kernel_end ) - { - /* No overlap, just check whether the region is large enough. = */ - if ( end - start >=3D size ) - return start; - } - /* Deal with the kernel already being loaded in the region. */ - else if ( kernel_start > start && kernel_start - start >=3D size ) - return start; - else if ( kernel_end < end && end - kernel_end >=3D size ) - return kernel_end; - } - - return INVALID_PADDR; -} - -static bool __init check_load_address( - const struct domain *d, const struct elf_binary *elf) -{ - paddr_t kernel_start =3D (uintptr_t)elf->dest_base; - paddr_t kernel_end =3D kernel_start + elf->dest_size; - unsigned int i; - - /* Relies on a sorted memory map with adjacent entries merged. */ - for ( i =3D 0; i < d->arch.nr_e820; i++ ) - { - paddr_t start =3D d->arch.e820[i].addr; - paddr_t end =3D start + d->arch.e820[i].size; - - if ( start >=3D kernel_end ) - return false; - - if ( d->arch.e820[i].type =3D=3D E820_RAM && - start <=3D kernel_start && - end >=3D kernel_end ) - return true; - } - - return false; -} - -/* Find an e820 RAM region that fits the kernel at a suitable alignment. */ -static paddr_t __init find_kernel_memory( - const struct domain *d, struct elf_binary *elf, - const struct elf_dom_parms *parms) -{ - paddr_t kernel_size =3D elf->dest_size; - unsigned int align; - unsigned int i; - - if ( parms->phys_align !=3D UNSET_ADDR32 ) - align =3D parms->phys_align; - else if ( elf->palign >=3D PAGE_SIZE ) - align =3D elf->palign; - else - align =3D MB(2); - - /* Search backwards to find the highest address. */ - for ( i =3D d->arch.nr_e820; i--; ) - { - paddr_t start =3D d->arch.e820[i].addr; - paddr_t end =3D start + d->arch.e820[i].size; - paddr_t kstart, kend; - - if ( d->arch.e820[i].type !=3D E820_RAM || - d->arch.e820[i].size < kernel_size ) - continue; - - if ( start > parms->phys_max ) - continue; - - if ( end - 1 > parms->phys_max ) - end =3D parms->phys_max + 1; - - kstart =3D (end - kernel_size) & ~(align - 1); - kend =3D kstart + kernel_size; - - if ( kstart < parms->phys_min ) - return 0; - - if ( kstart >=3D start && kend <=3D end ) - return kstart; - } - - return 0; -} - -/* Check the kernel load address, and adjust if necessary and possible. */ -static bool __init check_and_adjust_load_address( - const struct domain *d, struct elf_binary *elf, struct elf_dom_parms *= parms) -{ - paddr_t reloc_base; - - if ( check_load_address(d, elf) ) - return true; - - if ( !parms->phys_reloc ) - { - printk("%pd kernel: Address conflict and not relocatable\n", d); - return false; - } - - reloc_base =3D find_kernel_memory(d, elf, parms); - if ( !reloc_base ) - { - printk("%pd kernel: Failed find a load address\n", d); - return false; - } - - if ( opt_dom0_verbose ) - printk("%pd kernel: Moving [%p, %p] -> [%"PRIpaddr", %"PRIpaddr"]\= n", d, - elf->dest_base, elf->dest_base + elf->dest_size - 1, - reloc_base, reloc_base + elf->dest_size - 1); - - parms->phys_entry =3D - reloc_base + (parms->phys_entry - (uintptr_t)elf->dest_base); - elf->dest_base =3D (char *)reloc_base; - - return true; -} - -static int __init pvh_load_kernel( - const struct boot_domain *bd, paddr_t *entry, paddr_t *start_info_addr) -{ - struct domain *d =3D bd->d; - struct boot_module *image =3D bd->kernel; - struct boot_module *initrd =3D bd->ramdisk; - void *image_base =3D bootstrap_map_bm(image); - void *image_start =3D image_base + image->headroom; - unsigned long image_len =3D image->size; - unsigned long initrd_len =3D initrd ? initrd->size : 0; - const char *initrd_cmdline =3D NULL; - struct elf_binary elf; - struct elf_dom_parms parms; - size_t extra_space; - paddr_t last_addr; - struct hvm_start_info start_info =3D { 0 }; - struct hvm_modlist_entry mod =3D { 0 }; - struct vcpu *v =3D d->vcpu[0]; - int rc; - - if ( (rc =3D bzimage_parse(image_base, &image_start, &image_len)) !=3D= 0 ) - { - printk("Error trying to detect bz compressed kernel\n"); - return rc; - } - - if ( (rc =3D elf_init(&elf, image_start, image_len)) !=3D 0 ) - { - printk("Unable to init ELF\n"); - return rc; - } - if ( opt_dom0_verbose ) - elf_set_verbose(&elf); - elf_parse_binary(&elf); - if ( (rc =3D elf_xen_parse(&elf, &parms, true)) !=3D 0 ) - { - printk("Unable to parse kernel for ELFNOTES\n"); - if ( elf_check_broken(&elf) ) - printk("%pd kernel: broken ELF: %s\n", d, elf_check_broken(&el= f)); - return rc; - } - - if ( parms.phys_entry =3D=3D UNSET_ADDR32 ) - { - printk("Unable to find XEN_ELFNOTE_PHYS32_ENTRY address\n"); - return -EINVAL; - } - - /* Copy the OS image and free temporary buffer. */ - elf.dest_base =3D (void *)(parms.virt_kstart - parms.virt_base); - elf.dest_size =3D parms.virt_kend - parms.virt_kstart; - - if ( !check_and_adjust_load_address(d, &elf, &parms) ) - return -ENOSPC; - - elf_set_vcpu(&elf, v); - rc =3D elf_load_binary(&elf); - if ( rc < 0 ) - { - printk("Failed to load kernel: %d\n", rc); - if ( elf_check_broken(&elf) ) - printk("%pd kernel: broken ELF: %s\n", d, elf_check_broken(&el= f)); - return rc; - } - - /* - * Find a RAM region big enough (and that doesn't overlap with the loa= ded - * kernel) in order to load the initrd and the metadata. Note it could= be - * split into smaller allocations, done as a single region in order to - * simplify it. - */ - extra_space =3D sizeof(start_info); - - if ( initrd ) - { - size_t initrd_space =3D elf_round_up(&elf, initrd_len); - - if ( initrd->cmdline_pa ) - { - initrd_cmdline =3D __va(initrd->cmdline_pa); - if ( !*initrd_cmdline ) - initrd_cmdline =3D NULL; - } - if ( initrd_cmdline ) - initrd_space +=3D strlen(initrd_cmdline) + 1; - - if ( initrd_space ) - extra_space +=3D ROUNDUP(initrd_space, PAGE_SIZE) + sizeof(mod= ); - else - initrd =3D NULL; - } - - if ( bd->cmdline ) - extra_space +=3D elf_round_up(&elf, strlen(bd->cmdline) + 1); - - last_addr =3D find_memory(d, &elf, extra_space); - if ( last_addr =3D=3D INVALID_PADDR ) - { - printk("Unable to find a memory region to load initrd and metadata= \n"); - return -ENOMEM; - } - - if ( initrd !=3D NULL ) - { - rc =3D hvm_copy_to_guest_phys(last_addr, __va(initrd->start), - initrd_len, v); - if ( rc ) - { - printk("Unable to copy initrd to guest\n"); - return rc; - } - - mod.paddr =3D last_addr; - mod.size =3D initrd_len; - last_addr +=3D elf_round_up(&elf, initrd_len); - if ( initrd_cmdline ) - { - size_t len =3D strlen(initrd_cmdline) + 1; - - rc =3D hvm_copy_to_guest_phys(last_addr, initrd_cmdline, len, = v); - if ( rc ) - { - printk("Unable to copy module command line\n"); - return rc; - } - mod.cmdline_paddr =3D last_addr; - last_addr +=3D len; - } - last_addr =3D ROUNDUP(last_addr, PAGE_SIZE); - } - - /* Free temporary buffers. */ - free_boot_modules(); - - if ( bd->cmdline ) - { - rc =3D hvm_copy_to_guest_phys(last_addr, bd->cmdline, - strlen(bd->cmdline) + 1, v); - if ( rc ) - { - printk("Unable to copy guest command line\n"); - return rc; - } - start_info.cmdline_paddr =3D last_addr; - /* - * Round up to 32/64 bits (depending on the guest kernel bitness) = so - * the modlist/start_info is aligned. - */ - last_addr +=3D elf_round_up(&elf, strlen(bd->cmdline) + 1); - } - if ( initrd !=3D NULL ) - { - rc =3D hvm_copy_to_guest_phys(last_addr, &mod, sizeof(mod), v); - if ( rc ) - { - printk("Unable to copy guest modules\n"); - return rc; - } - start_info.modlist_paddr =3D last_addr; - start_info.nr_modules =3D 1; - last_addr +=3D sizeof(mod); - } - - start_info.magic =3D XEN_HVM_START_MAGIC_VALUE; - start_info.flags =3D SIF_PRIVILEGED | SIF_INITDOMAIN; - rc =3D hvm_copy_to_guest_phys(last_addr, &start_info, sizeof(start_inf= o), v); - if ( rc ) - { - printk("Unable to copy start info to guest\n"); - return rc; - } - - *entry =3D parms.phys_entry; - *start_info_addr =3D last_addr; - - return 0; -} - static int __init cf_check acpi_count_intr_ovr( struct acpi_subtable_header *header, const unsigned long end) { @@ -1255,42 +926,6 @@ int __init dom0_pvh_setup_acpi(struct domain *d, padd= r_t start_info) return 0; } =20 -int __init dom0_construct_pvh(struct boot_domain *bd) -{ - paddr_t entry, start_info; - struct domain *d =3D bd->d; - int rc; - - rc =3D pvh_load_kernel(bd, &entry, &start_info); - if ( rc ) - { - printk("Failed to load Dom0 kernel\n"); - return rc; - } - - rc =3D hvm_setup_cpus(bd->d, entry, start_info); - if ( rc ) - { - printk("Failed to setup Dom0 CPUs: %d\n", rc); - return rc; - } - - rc =3D dom0_pvh_setup_acpi(bd->d, start_info); - if ( rc ) - { - printk("Failed to setup Dom0 ACPI tables: %d\n", rc); - return rc; - } - - if ( opt_dom0_verbose ) - { - printk("Dom%u memory map:\n", d->domain_id); - print_e820_memory_map(d->arch.e820, d->arch.nr_e820); - } - - return 0; -} - /* * Local variables: * mode: C diff --git a/xen/arch/x86/hvm/dom_build.c b/xen/arch/x86/hvm/dom_build.c index 9421dc431ba9..2e47ca489a71 100644 --- a/xen/arch/x86/hvm/dom_build.c +++ b/xen/arch/x86/hvm/dom_build.c @@ -16,10 +16,12 @@ =20 #include =20 +#include #include #include =20 #include +#include #include #include #include @@ -276,8 +278,338 @@ static int __init hvm_populate_p2m(struct domain *d) return 0; } =20 +static paddr_t __init find_memory( + const struct domain *d, const struct elf_binary *elf, size_t size) +{ + paddr_t kernel_start =3D (paddr_t)elf->dest_base & PAGE_MASK; + paddr_t kernel_end =3D ROUNDUP((paddr_t)elf->dest_base + elf->dest_siz= e, + PAGE_SIZE); + unsigned int i; + + /* + * The memory map is sorted and all RAM regions starts and sizes are + * aligned to page boundaries. + */ + for ( i =3D 0; i < d->arch.nr_e820; i++ ) + { + paddr_t start, end =3D d->arch.e820[i].addr + d->arch.e820[i].size; + + /* Don't use memory below 1MB, as it could overwrite BDA/EBDA/IBFT= . */ + if ( end <=3D MB(1) || d->arch.e820[i].type !=3D E820_RAM ) + continue; + + start =3D MAX(ROUNDUP(d->arch.e820[i].addr, PAGE_SIZE), MB(1)); + + ASSERT(IS_ALIGNED(start, PAGE_SIZE) && IS_ALIGNED(end, PAGE_SIZE)); + + /* + * NB: Even better would be to use rangesets to determine a suitab= le + * range, in particular in case a kernel requests multiple heavily + * discontiguous regions (which right now we fold all into one big + * region). + */ + if ( end <=3D kernel_start || start >=3D kernel_end ) + { + /* No overlap, just check whether the region is large enough. = */ + if ( end - start >=3D size ) + return start; + } + /* Deal with the kernel already being loaded in the region. */ + else if ( kernel_start > start && kernel_start - start >=3D size ) + return start; + else if ( kernel_end < end && end - kernel_end >=3D size ) + return kernel_end; + } + + return INVALID_PADDR; +} + +static bool __init check_load_address( + const struct domain *d, const struct elf_binary *elf) +{ + paddr_t kernel_start =3D (uintptr_t)elf->dest_base; + paddr_t kernel_end =3D kernel_start + elf->dest_size; + unsigned int i; + + /* Relies on a sorted memory map with adjacent entries merged. */ + for ( i =3D 0; i < d->arch.nr_e820; i++ ) + { + paddr_t start =3D d->arch.e820[i].addr; + paddr_t end =3D start + d->arch.e820[i].size; + + if ( start >=3D kernel_end ) + return false; + + if ( d->arch.e820[i].type =3D=3D E820_RAM && + start <=3D kernel_start && + end >=3D kernel_end ) + return true; + } + + return false; +} + +/* Find an e820 RAM region that fits the kernel at a suitable alignment. */ +static paddr_t __init find_kernel_memory( + const struct domain *d, struct elf_binary *elf, + const struct elf_dom_parms *parms) +{ + paddr_t kernel_size =3D elf->dest_size; + unsigned int align; + unsigned int i; + + if ( parms->phys_align !=3D UNSET_ADDR32 ) + align =3D parms->phys_align; + else if ( elf->palign >=3D PAGE_SIZE ) + align =3D elf->palign; + else + align =3D MB(2); + + /* Search backwards to find the highest address. */ + for ( i =3D d->arch.nr_e820; i--; ) + { + paddr_t start =3D d->arch.e820[i].addr; + paddr_t end =3D start + d->arch.e820[i].size; + paddr_t kstart, kend; + + if ( d->arch.e820[i].type !=3D E820_RAM || + d->arch.e820[i].size < kernel_size ) + continue; + + if ( start > parms->phys_max ) + continue; + + if ( end - 1 > parms->phys_max ) + end =3D parms->phys_max + 1; + + kstart =3D (end - kernel_size) & ~(align - 1); + kend =3D kstart + kernel_size; + + if ( kstart < parms->phys_min ) + return 0; + + if ( kstart >=3D start && kend <=3D end ) + return kstart; + } + + return 0; +} + +/* Check the kernel load address, and adjust if necessary and possible. */ +static bool __init check_and_adjust_load_address( + const struct domain *d, struct elf_binary *elf, struct elf_dom_parms *= parms) +{ + paddr_t reloc_base; + + if ( check_load_address(d, elf) ) + return true; + + if ( !parms->phys_reloc ) + { + printk("%pd kernel: Address conflict and not relocatable\n", d); + return false; + } + + reloc_base =3D find_kernel_memory(d, elf, parms); + if ( !reloc_base ) + { + printk("%pd kernel: Failed find a load address\n", d); + return false; + } + + if ( opt_dom0_verbose ) + printk("%pd kernel: Moving [%p, %p] -> [%"PRIpaddr", %"PRIpaddr"]\= n", d, + elf->dest_base, elf->dest_base + elf->dest_size - 1, + reloc_base, reloc_base + elf->dest_size - 1); + + parms->phys_entry =3D + reloc_base + (parms->phys_entry - (uintptr_t)elf->dest_base); + elf->dest_base =3D (char *)reloc_base; + + return true; +} + +static int __init pvh_load_kernel( + const struct boot_domain *bd, paddr_t *entry, paddr_t *start_info_addr) +{ + struct domain *d =3D bd->d; + struct boot_module *image =3D bd->kernel; + struct boot_module *initrd =3D bd->ramdisk; + void *image_base =3D bootstrap_map_bm(image); + void *image_start =3D image_base + image->headroom; + unsigned long image_len =3D image->size; + unsigned long initrd_len =3D initrd ? initrd->size : 0; + const char *initrd_cmdline =3D NULL; + struct elf_binary elf; + struct elf_dom_parms parms; + size_t extra_space; + paddr_t last_addr; + struct hvm_start_info start_info =3D { 0 }; + struct hvm_modlist_entry mod =3D { 0 }; + struct vcpu *v =3D d->vcpu[0]; + int rc; + + if ( (rc =3D bzimage_parse(image_base, &image_start, &image_len)) !=3D= 0 ) + { + printk("Error trying to detect bz compressed kernel\n"); + return rc; + } + + if ( (rc =3D elf_init(&elf, image_start, image_len)) !=3D 0 ) + { + printk("Unable to init ELF\n"); + return rc; + } + if ( opt_dom0_verbose ) + elf_set_verbose(&elf); + elf_parse_binary(&elf); + if ( (rc =3D elf_xen_parse(&elf, &parms, true)) !=3D 0 ) + { + printk("Unable to parse kernel for ELFNOTES\n"); + if ( elf_check_broken(&elf) ) + printk("%pd kernel: broken ELF: %s\n", d, elf_check_broken(&el= f)); + return rc; + } + + if ( parms.phys_entry =3D=3D UNSET_ADDR32 ) + { + printk("Unable to find XEN_ELFNOTE_PHYS32_ENTRY address\n"); + return -EINVAL; + } + + /* Copy the OS image and free temporary buffer. */ + elf.dest_base =3D (void *)(parms.virt_kstart - parms.virt_base); + elf.dest_size =3D parms.virt_kend - parms.virt_kstart; + + if ( !check_and_adjust_load_address(d, &elf, &parms) ) + return -ENOSPC; + + elf_set_vcpu(&elf, v); + rc =3D elf_load_binary(&elf); + if ( rc < 0 ) + { + printk("Failed to load kernel: %d\n", rc); + if ( elf_check_broken(&elf) ) + printk("%pd kernel: broken ELF: %s\n", d, elf_check_broken(&el= f)); + return rc; + } + + /* + * Find a RAM region big enough (and that doesn't overlap with the loa= ded + * kernel) in order to load the initrd and the metadata. Note it could= be + * split into smaller allocations, done as a single region in order to + * simplify it. + */ + extra_space =3D sizeof(start_info); + + if ( initrd ) + { + size_t initrd_space =3D elf_round_up(&elf, initrd_len); + + if ( initrd->cmdline_pa ) + { + initrd_cmdline =3D __va(initrd->cmdline_pa); + if ( !*initrd_cmdline ) + initrd_cmdline =3D NULL; + } + if ( initrd_cmdline ) + initrd_space +=3D strlen(initrd_cmdline) + 1; + + if ( initrd_space ) + extra_space +=3D ROUNDUP(initrd_space, PAGE_SIZE) + sizeof(mod= ); + else + initrd =3D NULL; + } + + if ( bd->cmdline ) + extra_space +=3D elf_round_up(&elf, strlen(bd->cmdline) + 1); + + last_addr =3D find_memory(d, &elf, extra_space); + if ( last_addr =3D=3D INVALID_PADDR ) + { + printk("Unable to find a memory region to load initrd and metadata= \n"); + return -ENOMEM; + } + + if ( initrd !=3D NULL ) + { + rc =3D hvm_copy_to_guest_phys(last_addr, __va(initrd->start), + initrd_len, v); + if ( rc ) + { + printk("Unable to copy initrd to guest\n"); + return rc; + } + + mod.paddr =3D last_addr; + mod.size =3D initrd_len; + last_addr +=3D elf_round_up(&elf, initrd_len); + if ( initrd_cmdline ) + { + size_t len =3D strlen(initrd_cmdline) + 1; + + rc =3D hvm_copy_to_guest_phys(last_addr, initrd_cmdline, len, = v); + if ( rc ) + { + printk("Unable to copy module command line\n"); + return rc; + } + mod.cmdline_paddr =3D last_addr; + last_addr +=3D len; + } + last_addr =3D ROUNDUP(last_addr, PAGE_SIZE); + } + + /* Free temporary buffers. */ + free_boot_modules(); + + if ( bd->cmdline ) + { + rc =3D hvm_copy_to_guest_phys(last_addr, bd->cmdline, + strlen(bd->cmdline) + 1, v); + if ( rc ) + { + printk("Unable to copy guest command line\n"); + return rc; + } + start_info.cmdline_paddr =3D last_addr; + /* + * Round up to 32/64 bits (depending on the guest kernel bitness) = so + * the modlist/start_info is aligned. + */ + last_addr +=3D elf_round_up(&elf, strlen(bd->cmdline) + 1); + } + if ( initrd !=3D NULL ) + { + rc =3D hvm_copy_to_guest_phys(last_addr, &mod, sizeof(mod), v); + if ( rc ) + { + printk("Unable to copy guest modules\n"); + return rc; + } + start_info.modlist_paddr =3D last_addr; + start_info.nr_modules =3D 1; + last_addr +=3D sizeof(mod); + } + + start_info.magic =3D XEN_HVM_START_MAGIC_VALUE; + start_info.flags =3D SIF_PRIVILEGED | SIF_INITDOMAIN; + rc =3D hvm_copy_to_guest_phys(last_addr, &start_info, sizeof(start_inf= o), v); + if ( rc ) + { + printk("Unable to copy start info to guest\n"); + return rc; + } + + *entry =3D parms.phys_entry; + *start_info_addr =3D last_addr; + + return 0; +} + int __init dom_construct_pvh(struct boot_domain *bd) { + paddr_t entry, start_info; int rc; =20 printk(XENLOG_INFO "*** Building a PVH Dom%d ***\n", bd->domid); @@ -327,7 +659,35 @@ int __init dom_construct_pvh(struct boot_domain *bd) return rc; } =20 - return dom0_construct_pvh(bd); + rc =3D pvh_load_kernel(bd, &entry, &start_info); + if ( rc ) + { + printk("Failed to load Dom0 kernel\n"); + return rc; + } + + rc =3D hvm_setup_cpus(bd->d, entry, start_info); + if ( rc ) + { + printk("Failed to setup Dom0 CPUs: %d\n", rc); + return rc; + } + + rc =3D dom0_pvh_setup_acpi(bd->d, start_info); + if ( rc ) + { + printk("Failed to setup Dom0 ACPI tables: %d\n", rc); + return rc; + } + + if ( opt_dom0_verbose ) + { + printk("Dom%u memory map:\n", bd->domid); + print_e820_memory_map(bd->d->arch.e820, bd->d->arch.nr_e820); + } + + printk("WARNING: PVH is an experimental mode with limited functionalit= y\n"); + return 0; } =20 /* diff --git a/xen/arch/x86/include/asm/dom0_build.h b/xen/arch/x86/include/a= sm/dom0_build.h index 3819b3f4e7a4..6947aaa1dce3 100644 --- a/xen/arch/x86/include/asm/dom0_build.h +++ b/xen/arch/x86/include/asm/dom0_build.h @@ -24,7 +24,6 @@ int dom0_pvh_setup_acpi(struct domain *d, paddr_t start_i= nfo); int dom0_pvh_populate_p2m(struct domain *d); =20 int dom0_construct_pv(struct boot_domain *bd); -int dom0_construct_pvh(struct boot_domain *bd); =20 void dom0_update_physmap(bool compat, unsigned long pfn, unsigned long mfn, unsigned long vphysmap_s); --=20 2.30.2