From nobody Thu May 16 00:42:45 2024 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; 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; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1695823331703525.1857326086699; Wed, 27 Sep 2023 07:02:11 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.608948.947780 (Exim 4.92) (envelope-from ) id 1qlV6p-0006hR-Qu; Wed, 27 Sep 2023 14:01:47 +0000 Received: by outflank-mailman (output) from mailman id 608948.947780; Wed, 27 Sep 2023 14:01:47 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1qlV6p-0006gM-MS; Wed, 27 Sep 2023 14:01:47 +0000 Received: by outflank-mailman (input) for mailman id 608948; Wed, 27 Sep 2023 14:01:46 +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 1qlV6o-0006eS-Dy for xen-devel@lists.xenproject.org; Wed, 27 Sep 2023 14:01:46 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 63f97ad7-5d3e-11ee-878a-cb3800f73035; Wed, 27 Sep 2023 16:01:44 +0200 (CEST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id AAB1ADA7; Wed, 27 Sep 2023 07:02:21 -0700 (PDT) Received: from e125770.cambridge.arm.com (e125770.arm.com [10.1.199.1]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 81FC13F7C5; Wed, 27 Sep 2023 07:01:42 -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: 63f97ad7-5d3e-11ee-878a-cb3800f73035 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: wei.chen@arm.com, Stefano Stabellini , Julien Grall , Bertrand Marquis , Volodymyr Babchuk , Julien Grall , Michal Orzel Subject: [PATCH v2 1/5] arm/gicv2: make GICv2 driver and vGICv2 optional Date: Wed, 27 Sep 2023 15:01:29 +0100 Message-Id: <20230927140133.631192-2-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230927140133.631192-1-luca.fancellu@arm.com> References: <20230927140133.631192-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1695823334055100001 Content-Type: text/plain; charset="utf-8" Introduce Kconfig GICV2 to be able to compile the GICv2 driver only when needed, the option is active by default. Introduce Kconfig VGICV2 that compiles the Generic Interrupt Controller v2 emulation for domains, it is required only when using GICv2 driver, otherwise using the GICv3 driver it is optional and can be deselected if the user doesn't want to offer the v2 emulation to domains or maybe its GICv3 hardware can't offer the GICv2 compatible mode. Signed-off-by: Luca Fancellu Reviewed-by: Julien Grall Reviewed-by: Michal Orzel --- xen/arch/arm/Kconfig | 19 +++++++++++++++++++ xen/arch/arm/Makefile | 4 ++-- xen/arch/arm/domain_build.c | 4 ++++ xen/arch/arm/gic-v3.c | 4 ++++ xen/arch/arm/vgic.c | 2 ++ xen/arch/arm/vgic/Makefile | 4 ++-- 6 files changed, 33 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index 632dd9792e3c..8dc704e802bc 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -81,6 +81,14 @@ config ARM_EFI UEFI firmware. A UEFI stub is provided to allow Xen to be booted as an EFI application. =20 +config GICV2 + bool "GICv2 driver" + default y + select VGICV2 + help + Driver for the ARM Generic Interrupt Controller v2. + If unsure, say Y + config GICV3 bool "GICv3 driver" depends on !NEW_VGIC @@ -100,11 +108,22 @@ config OVERLAY_DTB help Dynamic addition/removal of Xen device tree nodes using a dtbo. =20 +config VGICV2 + bool "vGICv2 interface for domains" + default y + help + Allow Xen to expose a Generic Interrupt Controller version 2 like to Xen + domains. This can be configured at the domain creation. + This option is mandatory when using GICv2. + For GICv3, this allows domain to use GICv2 when the hardware supports i= t. + If unsure say Y. + config HVM def_bool y =20 config NEW_VGIC bool "Use new VGIC implementation" + select GICV2 ---help--- =20 This is an alternative implementation of the ARM GIC interrupt diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 7bf07e992046..81c31c36fc3d 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -22,7 +22,7 @@ obj-y +=3D domctl.o obj-$(CONFIG_EARLY_PRINTK) +=3D early_printk.o obj-y +=3D efi/ obj-y +=3D gic.o -obj-y +=3D gic-v2.o +obj-$(CONFIG_GICV2) +=3D gic-v2.o obj-$(CONFIG_GICV3) +=3D gic-v3.o obj-$(CONFIG_HAS_ITS) +=3D gic-v3-its.o obj-$(CONFIG_HAS_ITS) +=3D gic-v3-lpi.o @@ -57,7 +57,7 @@ obj-$(CONFIG_NEW_VGIC) +=3D vgic/ ifneq ($(CONFIG_NEW_VGIC),y) obj-y +=3D gic-vgic.o obj-y +=3D vgic.o -obj-y +=3D vgic-v2.o +obj-$(CONFIG_VGICV2) +=3D vgic-v2.o obj-$(CONFIG_GICV3) +=3D vgic-v3.o obj-$(CONFIG_HAS_ITS) +=3D vgic-v3-its.o endif diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 24c9019cc43c..f69f238ccea4 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -2490,6 +2490,7 @@ static int __init handle_node(struct domain *d, struc= t kernel_info *kinfo, return res; } =20 +#ifdef CONFIG_VGICV2 static int __init make_gicv2_domU_node(struct kernel_info *kinfo) { void *fdt =3D kinfo->fdt; @@ -2541,6 +2542,7 @@ static int __init make_gicv2_domU_node(struct kernel_= info *kinfo) =20 return res; } +#endif =20 #ifdef CONFIG_GICV3 static int __init make_gicv3_domU_node(struct kernel_info *kinfo) @@ -2616,8 +2618,10 @@ static int __init make_gic_domU_node(struct kernel_i= nfo *kinfo) case GIC_V3: return make_gicv3_domU_node(kinfo); #endif +#ifdef CONFIG_VGICV2 case GIC_V2: return make_gicv2_domU_node(kinfo); +#endif default: panic("Unsupported GIC version\n"); } diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 95e4f020febe..d18a3317ccc4 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1334,6 +1334,7 @@ static paddr_t __initdata dbase =3D INVALID_PADDR; static paddr_t __initdata vbase =3D INVALID_PADDR, vsize =3D 0; static paddr_t __initdata cbase =3D INVALID_PADDR, csize =3D 0; =20 +#ifdef CONFIG_VGICV2 /* If the GICv3 supports GICv2, initialize it */ static void __init gicv3_init_v2(void) { @@ -1359,6 +1360,9 @@ static void __init gicv3_init_v2(void) =20 vgic_v2_setup_hw(dbase, cbase, csize, vbase, 0); } +#else +static inline void gicv3_init_v2(void) { } +#endif =20 static void __init gicv3_ioremap_distributor(paddr_t dist_paddr) { diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index f6b49766f97a..c04fc4f83f96 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -96,10 +96,12 @@ int domain_vgic_register(struct domain *d, unsigned int= *mmio_count) return -ENODEV; break; #endif +#ifdef CONFIG_VGICV2 case GIC_V2: if ( vgic_v2_init(d, mmio_count) ) return -ENODEV; break; +#endif default: printk(XENLOG_G_ERR "d%d: Unknown vGIC version %u\n", d->domain_id, d->arch.vgic.version); diff --git a/xen/arch/arm/vgic/Makefile b/xen/arch/arm/vgic/Makefile index 806826948e20..60cbf7f2f94a 100644 --- a/xen/arch/arm/vgic/Makefile +++ b/xen/arch/arm/vgic/Makefile @@ -1,5 +1,5 @@ obj-y +=3D vgic.o -obj-y +=3D vgic-v2.o +obj-$(CONFIG_VGICV2) +=3D vgic-v2.o obj-y +=3D vgic-mmio.o -obj-y +=3D vgic-mmio-v2.o +obj-$(CONFIG_VGICV2) +=3D vgic-mmio-v2.o obj-y +=3D vgic-init.o --=20 2.34.1 From nobody Thu May 16 00:42:45 2024 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; 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; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1695823335151206.54085482000073; Wed, 27 Sep 2023 07:02:15 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.608949.947788 (Exim 4.92) (envelope-from ) id 1qlV6q-0006u8-AN; Wed, 27 Sep 2023 14:01:48 +0000 Received: by outflank-mailman (output) from mailman id 608949.947788; Wed, 27 Sep 2023 14:01:48 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1qlV6q-0006r2-5q; Wed, 27 Sep 2023 14:01:48 +0000 Received: by outflank-mailman (input) for mailman id 608949; Wed, 27 Sep 2023 14:01:47 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1qlV6p-0006dA-0D for xen-devel@lists.xenproject.org; Wed, 27 Sep 2023 14:01:47 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 649554e8-5d3e-11ee-9b0d-b553b5be7939; Wed, 27 Sep 2023 16:01:45 +0200 (CEST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id B98BB11FB; Wed, 27 Sep 2023 07:02:22 -0700 (PDT) Received: from e125770.cambridge.arm.com (e125770.arm.com [10.1.199.1]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id C45953F7C5; Wed, 27 Sep 2023 07:01:43 -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: 649554e8-5d3e-11ee-9b0d-b553b5be7939 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: wei.chen@arm.com, Stefano Stabellini , Julien Grall , Bertrand Marquis , Volodymyr Babchuk Subject: [PATCH v2 2/5] xen/arm: Add asm/domain.h include to kernel.h Date: Wed, 27 Sep 2023 15:01:30 +0100 Message-Id: <20230927140133.631192-3-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230927140133.631192-1-luca.fancellu@arm.com> References: <20230927140133.631192-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1695823336204100005 Content-Type: text/plain; charset="utf-8" The 'enum domain_type' is defined by 'asm/domain.h' which is not included (directly or indirectly) by 'asm/kernel.h'. This currently doesn't break the compilation because asm/domain.h will included by the user of 'kernel.h'. But it would be better to avoid relying on it. So add the include in 'asm/domain.h'. Signed-off-by: Luca Fancellu Acked-by: Julien Grall --- Changes from v1: - Rephrased commit message (Julien) --- xen/arch/arm/include/asm/kernel.h | 1 + 1 file changed, 1 insertion(+) diff --git a/xen/arch/arm/include/asm/kernel.h b/xen/arch/arm/include/asm/k= ernel.h index 4617cdc83bac..0a23e86c2d37 100644 --- a/xen/arch/arm/include/asm/kernel.h +++ b/xen/arch/arm/include/asm/kernel.h @@ -7,6 +7,7 @@ #define __ARCH_ARM_KERNEL_H__ =20 #include +#include #include =20 /* --=20 2.34.1 From nobody Thu May 16 00:42:45 2024 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; 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; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 16958233387341015.367401935627; Wed, 27 Sep 2023 07:02:18 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.608950.947806 (Exim 4.92) (envelope-from ) id 1qlV6t-0007Q1-It; Wed, 27 Sep 2023 14:01:51 +0000 Received: by outflank-mailman (output) from mailman id 608950.947806; Wed, 27 Sep 2023 14:01:51 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1qlV6t-0007Po-FL; Wed, 27 Sep 2023 14:01:51 +0000 Received: by outflank-mailman (input) for mailman id 608950; Wed, 27 Sep 2023 14:01:50 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1qlV6s-0006dA-5c for xen-devel@lists.xenproject.org; Wed, 27 Sep 2023 14:01:50 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 6566619c-5d3e-11ee-9b0d-b553b5be7939; Wed, 27 Sep 2023 16:01:46 +0200 (CEST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 2731E1FB; Wed, 27 Sep 2023 07:02:24 -0700 (PDT) Received: from e125770.cambridge.arm.com (e125770.arm.com [10.1.199.1]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id D744C3F59C; Wed, 27 Sep 2023 07:01:44 -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: 6566619c-5d3e-11ee-9b0d-b553b5be7939 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: wei.chen@arm.com, Stefano Stabellini , Julien Grall , Bertrand Marquis , Volodymyr Babchuk Subject: [PATCH v2 3/5] arm/dom0less: put dom0less feature code in a separate module Date: Wed, 27 Sep 2023 15:01:31 +0100 Message-Id: <20230927140133.631192-4-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230927140133.631192-1-luca.fancellu@arm.com> References: <20230927140133.631192-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1695823340030100001 Content-Type: text/plain; charset="utf-8" Currently the dom0less feature code is mostly inside domain_build.c and setup.c, it is a feature that may not be useful to everyone so put the code in a different compilation module in order to make it easier to disable the feature in the future. Move gic_interrupt_t in domain_build.h to use it with the function declaration, move its comment above the declaration. The following functions are now visible externally from domain_build because they are used also from the dom0less-build module: - get_allocation_size - set_interrupt - domain_fdt_begin_node - make_memory_node - make_resv_memory_node - make_hypervisor_node - make_psci_node - make_cpus_node - make_timer_node - handle_device_interrupts - construct_domain - process_shm The functions allocate_static_memory and assign_static_memory_11 are now externally visible, so put their declarations into domain_build.h and move the #else and stub definition in the header as well. Move is_dom0less_mode from setup.c to dom0less-build.c and make it externally visible. Where spotted, fix code style issues. No functional change is intended. Signed-off-by: Luca Fancellu --- xen/arch/arm/Makefile | 1 + xen/arch/arm/dom0less-build.c | 1087 ++++++++++++++++++ xen/arch/arm/domain_build.c | 1276 ++------------------- xen/arch/arm/include/asm/dom0less-build.h | 25 + xen/arch/arm/include/asm/domain_build.h | 58 + xen/arch/arm/include/asm/setup.h | 1 - xen/arch/arm/setup.c | 33 +- 7 files changed, 1288 insertions(+), 1193 deletions(-) create mode 100644 xen/arch/arm/dom0less-build.c create mode 100644 xen/arch/arm/include/asm/dom0less-build.h diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 81c31c36fc3d..70dd7201ef30 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -15,6 +15,7 @@ obj-y +=3D cpufeature.o obj-y +=3D decode.o obj-y +=3D device.o obj-$(CONFIG_IOREQ_SERVER) +=3D dm.o +obj-y +=3D dom0less-build.init.o obj-y +=3D domain.o obj-y +=3D domain_build.init.o obj-$(CONFIG_ARCH_MAP_DOMAIN_PAGE) +=3D domain_page.o diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c new file mode 100644 index 000000000000..dc9c90cf00a7 --- /dev/null +++ b/xen/arch/arm/dom0less-build.c @@ -0,0 +1,1087 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * xen/arch/arm/dom0less-build.c + * + * Code related to the dom0less functionality + * + * Copyright (C) 2023 Arm Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +bool __init is_dom0less_mode(void) +{ + struct bootmodules *mods =3D &bootinfo.modules; + struct bootmodule *mod; + unsigned int i; + bool dom0found =3D false; + bool domUfound =3D false; + + /* Look into the bootmodules */ + for ( i =3D 0 ; i < mods->nr_mods ; i++ ) + { + mod =3D &mods->module[i]; + /* Find if dom0 and domU kernels are present */ + if ( mod->kind =3D=3D BOOTMOD_KERNEL ) + { + if ( mod->domU =3D=3D false ) + { + dom0found =3D true; + break; + } + else + domUfound =3D true; + } + } + + /* + * If there is no dom0 kernel but at least one domU, then we are in + * dom0less mode + */ + return ( !dom0found && domUfound ); +} + +static bool __init allocate_bank_memory(struct domain *d, + struct kernel_info *kinfo, + gfn_t sgfn, + paddr_t tot_size) +{ + int res; + struct page_info *pg; + struct membank *bank; + unsigned int max_order =3D ~0; + + /* + * allocate_bank_memory can be called with a tot_size of zero for + * the second memory bank. It is not an error and we can safely + * avoid creating a zero-size memory bank. + */ + if ( tot_size =3D=3D 0 ) + return true; + + bank =3D &kinfo->mem.bank[kinfo->mem.nr_banks]; + bank->start =3D gfn_to_gaddr(sgfn); + bank->size =3D tot_size; + + while ( tot_size > 0 ) + { + unsigned int order =3D get_allocation_size(tot_size); + + order =3D min(max_order, order); + + pg =3D alloc_domheap_pages(d, order, 0); + if ( !pg ) + { + /* + * If we can't allocate one page, then it is unlikely to + * succeed in the next iteration. So bail out. + */ + if ( !order ) + return false; + + /* + * If we can't allocate memory with order, then it is + * unlikely to succeed in the next iteration. + * Record the order - 1 to avoid re-trying. + */ + max_order =3D order - 1; + continue; + } + + res =3D guest_physmap_add_page(d, sgfn, page_to_mfn(pg), order); + if ( res ) + { + dprintk(XENLOG_ERR, "Failed map pages to DOMU: %d", res); + return false; + } + + sgfn =3D gfn_add(sgfn, 1UL << order); + tot_size -=3D (1ULL << (PAGE_SHIFT + order)); + } + + kinfo->mem.nr_banks++; + kinfo->unassigned_mem -=3D bank->size; + + return true; +} + +static void __init allocate_memory(struct domain *d, struct kernel_info *k= info) +{ + unsigned int i; + paddr_t bank_size; + + printk(XENLOG_INFO "Allocating mappings totalling %ldMB for %pd:\n", + /* Don't want format this as PRIpaddr (16 digit hex) */ + (unsigned long)(kinfo->unassigned_mem >> 20), d); + + kinfo->mem.nr_banks =3D 0; + bank_size =3D MIN(GUEST_RAM0_SIZE, kinfo->unassigned_mem); + if ( !allocate_bank_memory(d, kinfo, gaddr_to_gfn(GUEST_RAM0_BASE), + bank_size) ) + goto fail; + + bank_size =3D MIN(GUEST_RAM1_SIZE, kinfo->unassigned_mem); + if ( !allocate_bank_memory(d, kinfo, gaddr_to_gfn(GUEST_RAM1_BASE), + bank_size) ) + goto fail; + + if ( kinfo->unassigned_mem ) + goto fail; + + for( i =3D 0; i < kinfo->mem.nr_banks; i++ ) + { + printk(XENLOG_INFO "%pd BANK[%d] %#"PRIpaddr"-%#"PRIpaddr" (%ldMB)= \n", + d, + i, + kinfo->mem.bank[i].start, + kinfo->mem.bank[i].start + kinfo->mem.bank[i].size, + /* Don't want format this as PRIpaddr (16 digit hex) */ + (unsigned long)(kinfo->mem.bank[i].size >> 20)); + } + + return; + +fail: + panic("Failed to allocate requested domain memory." + /* Don't want format this as PRIpaddr (16 digit hex) */ + " %ldKB unallocated. Fix the VMs configurations.\n", + (unsigned long)kinfo->unassigned_mem >> 10); +} + +#ifdef CONFIG_VGICV2 +static int __init make_gicv2_domU_node(struct kernel_info *kinfo) +{ + void *fdt =3D kinfo->fdt; + int res =3D 0; + __be32 reg[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) * 2]; + __be32 *cells; + const struct domain *d =3D kinfo->d; + + res =3D domain_fdt_begin_node(fdt, "interrupt-controller", + vgic_dist_base(&d->arch.vgic)); + if ( res ) + return res; + + res =3D fdt_property_cell(fdt, "#address-cells", 0); + if ( res ) + return res; + + res =3D fdt_property_cell(fdt, "#interrupt-cells", 3); + if ( res ) + return res; + + res =3D fdt_property(fdt, "interrupt-controller", NULL, 0); + if ( res ) + return res; + + res =3D fdt_property_string(fdt, "compatible", "arm,gic-400"); + if ( res ) + return res; + + cells =3D ®[0]; + dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_C= ELLS, + vgic_dist_base(&d->arch.vgic), GUEST_GICD_SIZE); + dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_C= ELLS, + vgic_cpu_base(&d->arch.vgic), GUEST_GICC_SIZE); + + res =3D fdt_property(fdt, "reg", reg, sizeof(reg)); + if (res) + return res; + + res =3D fdt_property_cell(fdt, "linux,phandle", kinfo->phandle_gic); + if (res) + return res; + + res =3D fdt_property_cell(fdt, "phandle", kinfo->phandle_gic); + if (res) + return res; + + res =3D fdt_end_node(fdt); + + return res; +} +#endif + +#ifdef CONFIG_GICV3 +static int __init make_gicv3_domU_node(struct kernel_info *kinfo) +{ + void *fdt =3D kinfo->fdt; + int res =3D 0; + __be32 *reg, *cells; + const struct domain *d =3D kinfo->d; + unsigned int i, len =3D 0; + + res =3D domain_fdt_begin_node(fdt, "interrupt-controller", + vgic_dist_base(&d->arch.vgic)); + if ( res ) + return res; + + res =3D fdt_property_cell(fdt, "#address-cells", 0); + if ( res ) + return res; + + res =3D fdt_property_cell(fdt, "#interrupt-cells", 3); + if ( res ) + return res; + + res =3D fdt_property(fdt, "interrupt-controller", NULL, 0); + if ( res ) + return res; + + res =3D fdt_property_string(fdt, "compatible", "arm,gic-v3"); + if ( res ) + return res; + + /* reg specifies all re-distributors and Distributor. */ + len =3D (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) * + (d->arch.vgic.nr_regions + 1) * sizeof(__be32); + reg =3D xmalloc_bytes(len); + if ( reg =3D=3D NULL ) + return -ENOMEM; + cells =3D reg; + + dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_C= ELLS, + vgic_dist_base(&d->arch.vgic), GUEST_GICV3_GICD_SIZ= E); + + for ( i =3D 0; i < d->arch.vgic.nr_regions; i++ ) + dt_child_set_range(&cells, + GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS, + d->arch.vgic.rdist_regions[i].base, + d->arch.vgic.rdist_regions[i].size); + + res =3D fdt_property(fdt, "reg", reg, len); + xfree(reg); + if (res) + return res; + + res =3D fdt_property_cell(fdt, "linux,phandle", kinfo->phandle_gic); + if (res) + return res; + + res =3D fdt_property_cell(fdt, "phandle", kinfo->phandle_gic); + if (res) + return res; + + res =3D fdt_end_node(fdt); + + return res; +} +#endif + +static int __init make_gic_domU_node(struct kernel_info *kinfo) +{ + switch ( kinfo->d->arch.vgic.version ) + { +#ifdef CONFIG_GICV3 + case GIC_V3: + return make_gicv3_domU_node(kinfo); +#endif +#ifdef CONFIG_VGICV2 + case GIC_V2: + return make_gicv2_domU_node(kinfo); +#endif + default: + panic("Unsupported GIC version\n"); + } +} + +#ifdef CONFIG_SBSA_VUART_CONSOLE +static int __init make_vpl011_uart_node(struct kernel_info *kinfo) +{ + void *fdt =3D kinfo->fdt; + int res; + gic_interrupt_t intr; + __be32 reg[GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS]; + __be32 *cells; + struct domain *d =3D kinfo->d; + + res =3D domain_fdt_begin_node(fdt, "sbsa-uart", d->arch.vpl011.base_ad= dr); + if ( res ) + return res; + + res =3D fdt_property_string(fdt, "compatible", "arm,sbsa-uart"); + if ( res ) + return res; + + cells =3D ®[0]; + dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, + GUEST_ROOT_SIZE_CELLS, d->arch.vpl011.base_addr, + GUEST_PL011_SIZE); + + res =3D fdt_property(fdt, "reg", reg, sizeof(reg)); + if ( res ) + return res; + + set_interrupt(intr, d->arch.vpl011.virq, 0xf, DT_IRQ_TYPE_LEVEL_HIGH); + + res =3D fdt_property(fdt, "interrupts", intr, sizeof (intr)); + if ( res ) + return res; + + res =3D fdt_property_cell(fdt, "interrupt-parent", + kinfo->phandle_gic); + if ( res ) + return res; + + /* Use a default baud rate of 115200. */ + fdt_property_u32(fdt, "current-speed", 115200); + + res =3D fdt_end_node(fdt); + if ( res ) + return res; + + return 0; +} +#endif + +/* + * Scan device tree properties for passthrough specific information. + * Returns < 0 on error + * 0 on success + */ +static int __init handle_passthrough_prop(struct kernel_info *kinfo, + const struct fdt_property *xen_r= eg, + const struct fdt_property *xen_p= ath, + bool xen_force, + uint32_t address_cells, + uint32_t size_cells) +{ + const __be32 *cell; + unsigned int i, len; + struct dt_device_node *node; + int res; + paddr_t mstart, size, gstart; + + /* xen,reg specifies where to map the MMIO region */ + cell =3D (const __be32 *)xen_reg->data; + len =3D fdt32_to_cpu(xen_reg->len) / ((address_cells * 2 + size_cells)= * + sizeof(uint32_t)); + + for ( i =3D 0; i < len; i++ ) + { + device_tree_get_reg(&cell, address_cells, size_cells, + &mstart, &size); + gstart =3D dt_next_cell(address_cells, &cell); + + if ( gstart & ~PAGE_MASK || mstart & ~PAGE_MASK || size & ~PAGE_MA= SK ) + { + printk(XENLOG_ERR + "DomU passthrough config has not page aligned addresses= /sizes\n"); + return -EINVAL; + } + + res =3D iomem_permit_access(kinfo->d, paddr_to_pfn(mstart), + paddr_to_pfn(PAGE_ALIGN(mstart + size - = 1))); + if ( res ) + { + printk(XENLOG_ERR "Unable to permit to dom%d access to" + " 0x%"PRIpaddr" - 0x%"PRIpaddr"\n", + kinfo->d->domain_id, + mstart & PAGE_MASK, PAGE_ALIGN(mstart + size) - 1); + return res; + } + + res =3D map_regions_p2mt(kinfo->d, + gaddr_to_gfn(gstart), + PFN_DOWN(size), + maddr_to_mfn(mstart), + p2m_mmio_direct_dev); + if ( res < 0 ) + { + printk(XENLOG_ERR + "Failed to map %"PRIpaddr" to the guest at%"PRIpaddr"\n= ", + mstart, gstart); + return -EFAULT; + } + } + + /* + * If xen_force, we let the user assign a MMIO region with no + * associated path. + */ + if ( xen_path =3D=3D NULL ) + return xen_force ? 0 : -EINVAL; + + /* + * xen,path specifies the corresponding node in the host DT. + * Both interrupt mappings and IOMMU settings are based on it, + * as they are done based on the corresponding host DT node. + */ + node =3D dt_find_node_by_path(xen_path->data); + if ( node =3D=3D NULL ) + { + printk(XENLOG_ERR "Couldn't find node %s in host_dt!\n", + (char *)xen_path->data); + return -EINVAL; + } + + res =3D map_device_irqs_to_domain(kinfo->d, node, true, NULL); + if ( res < 0 ) + return res; + + res =3D iommu_add_dt_device(node); + if ( res < 0 ) + return res; + + /* If xen_force, we allow assignment of devices without IOMMU protecti= on. */ + if ( xen_force && !dt_device_is_protected(node) ) + return 0; + + return iommu_assign_dt_device(kinfo->d, node); +} + +static int __init handle_prop_pfdt(struct kernel_info *kinfo, + const void *pfdt, int nodeoff, + uint32_t address_cells, uint32_t size_c= ells, + bool scan_passthrough_prop) +{ + void *fdt =3D kinfo->fdt; + int propoff, nameoff, res; + const struct fdt_property *prop, *xen_reg =3D NULL, *xen_path =3D NULL; + const char *name; + bool found, xen_force =3D false; + + for ( propoff =3D fdt_first_property_offset(pfdt, nodeoff); + propoff >=3D 0; + propoff =3D fdt_next_property_offset(pfdt, propoff) ) + { + if ( !(prop =3D fdt_get_property_by_offset(pfdt, propoff, NULL)) ) + return -FDT_ERR_INTERNAL; + + found =3D false; + nameoff =3D fdt32_to_cpu(prop->nameoff); + name =3D fdt_string(pfdt, nameoff); + + if ( scan_passthrough_prop ) + { + if ( dt_prop_cmp("xen,reg", name) =3D=3D 0 ) + { + xen_reg =3D prop; + found =3D true; + } + else if ( dt_prop_cmp("xen,path", name) =3D=3D 0 ) + { + xen_path =3D prop; + found =3D true; + } + else if ( dt_prop_cmp("xen,force-assign-without-iommu", + name) =3D=3D 0 ) + { + xen_force =3D true; + found =3D true; + } + } + + /* + * Copy properties other than the ones above: xen,reg, xen,path, + * and xen,force-assign-without-iommu. + */ + if ( !found ) + { + res =3D fdt_property(fdt, name, prop->data, fdt32_to_cpu(prop-= >len)); + if ( res ) + return res; + } + } + + /* + * Only handle passthrough properties if both xen,reg and xen,path + * are present, or if xen,force-assign-without-iommu is specified. + */ + if ( xen_reg !=3D NULL && (xen_path !=3D NULL || xen_force) ) + { + res =3D handle_passthrough_prop(kinfo, xen_reg, xen_path, xen_forc= e, + address_cells, size_cells); + if ( res < 0 ) + { + printk(XENLOG_ERR "Failed to assign device to %pd\n", kinfo->d= ); + return res; + } + } + else if ( (xen_path && !xen_reg) || (xen_reg && !xen_path && !xen_forc= e) ) + { + printk(XENLOG_ERR "xen,reg or xen,path missing for %pd\n", + kinfo->d); + return -EINVAL; + } + + /* FDT_ERR_NOTFOUND =3D> There is no more properties for this node */ + return ( propoff !=3D -FDT_ERR_NOTFOUND ) ? propoff : 0; +} + +static int __init scan_pfdt_node(struct kernel_info *kinfo, const void *pf= dt, + int nodeoff, + uint32_t address_cells, uint32_t size_cel= ls, + bool scan_passthrough_prop) +{ + int rc =3D 0; + void *fdt =3D kinfo->fdt; + int node_next; + + rc =3D fdt_begin_node(fdt, fdt_get_name(pfdt, nodeoff, NULL)); + if ( rc ) + return rc; + + rc =3D handle_prop_pfdt(kinfo, pfdt, nodeoff, address_cells, size_cell= s, + scan_passthrough_prop); + if ( rc ) + return rc; + + address_cells =3D device_tree_get_u32(pfdt, nodeoff, "#address-cells", + DT_ROOT_NODE_ADDR_CELLS_DEFAULT); + size_cells =3D device_tree_get_u32(pfdt, nodeoff, "#size-cells", + DT_ROOT_NODE_SIZE_CELLS_DEFAULT); + + node_next =3D fdt_first_subnode(pfdt, nodeoff); + while ( node_next > 0 ) + { + scan_pfdt_node(kinfo, pfdt, node_next, address_cells, size_cells, + scan_passthrough_prop); + node_next =3D fdt_next_subnode(pfdt, node_next); + } + + return fdt_end_node(fdt); +} + +static int __init check_partial_fdt(void *pfdt, size_t size) +{ + int res; + + if ( fdt_magic(pfdt) !=3D FDT_MAGIC ) + { + dprintk(XENLOG_ERR, "Partial FDT is not a valid Flat Device Tree"); + return -EINVAL; + } + + res =3D fdt_check_header(pfdt); + if ( res ) + { + dprintk(XENLOG_ERR, "Failed to check the partial FDT (%d)", res); + return -EINVAL; + } + + if ( fdt_totalsize(pfdt) > size ) + { + dprintk(XENLOG_ERR, "Partial FDT totalsize is too big"); + return -EINVAL; + } + + return 0; +} + +static int __init domain_handle_dtb_bootmodule(struct domain *d, + struct kernel_info *kinfo) +{ + void *pfdt; + int res, node_next; + + pfdt =3D ioremap_cache(kinfo->dtb_bootmodule->start, + kinfo->dtb_bootmodule->size); + if ( pfdt =3D=3D NULL ) + return -EFAULT; + + res =3D check_partial_fdt(pfdt, kinfo->dtb_bootmodule->size); + if ( res < 0 ) + goto out; + + for ( node_next =3D fdt_first_subnode(pfdt, 0); + node_next > 0; + node_next =3D fdt_next_subnode(pfdt, node_next) ) + { + const char *name =3D fdt_get_name(pfdt, node_next, NULL); + + if ( name =3D=3D NULL ) + continue; + + /* + * Only scan /gic /aliases /passthrough, ignore the rest. + * They don't have to be parsed in order. + * + * Take the GIC phandle value from the special /gic node in the + * DTB fragment. + */ + if ( dt_node_cmp(name, "gic") =3D=3D 0 ) + { + kinfo->phandle_gic =3D fdt_get_phandle(pfdt, node_next); + continue; + } + + if ( dt_node_cmp(name, "aliases") =3D=3D 0 ) + { + res =3D scan_pfdt_node(kinfo, pfdt, node_next, + DT_ROOT_NODE_ADDR_CELLS_DEFAULT, + DT_ROOT_NODE_SIZE_CELLS_DEFAULT, + false); + if ( res ) + goto out; + continue; + } + if ( dt_node_cmp(name, "passthrough") =3D=3D 0 ) + { + res =3D scan_pfdt_node(kinfo, pfdt, node_next, + DT_ROOT_NODE_ADDR_CELLS_DEFAULT, + DT_ROOT_NODE_SIZE_CELLS_DEFAULT, + true); + if ( res ) + goto out; + continue; + } + } + + out: + iounmap(pfdt); + + return res; +} + +/* + * The max size for DT is 2MB. However, the generated DT is small (not inc= luding + * domU passthrough DT nodes whose size we account separately), 4KB are en= ough + * for now, but we might have to increase it in the future. + */ +#define DOMU_DTB_SIZE 4096 +static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *k= info) +{ + int addrcells, sizecells; + int ret, fdt_size =3D DOMU_DTB_SIZE; + + kinfo->phandle_gic =3D GUEST_PHANDLE_GIC; + kinfo->gnttab_start =3D GUEST_GNTTAB_BASE; + kinfo->gnttab_size =3D GUEST_GNTTAB_SIZE; + + addrcells =3D GUEST_ROOT_ADDRESS_CELLS; + sizecells =3D GUEST_ROOT_SIZE_CELLS; + + /* Account for domU passthrough DT size */ + if ( kinfo->dtb_bootmodule ) + fdt_size +=3D kinfo->dtb_bootmodule->size; + + /* Cap to max DT size if needed */ + fdt_size =3D min(fdt_size, SZ_2M); + + kinfo->fdt =3D xmalloc_bytes(fdt_size); + if ( kinfo->fdt =3D=3D NULL ) + return -ENOMEM; + + ret =3D fdt_create(kinfo->fdt, fdt_size); + if ( ret < 0 ) + goto err; + + ret =3D fdt_finish_reservemap(kinfo->fdt); + if ( ret < 0 ) + goto err; + + ret =3D fdt_begin_node(kinfo->fdt, ""); + if ( ret < 0 ) + goto err; + + ret =3D fdt_property_cell(kinfo->fdt, "#address-cells", addrcells); + if ( ret ) + goto err; + + ret =3D fdt_property_cell(kinfo->fdt, "#size-cells", sizecells); + if ( ret ) + goto err; + + ret =3D make_chosen_node(kinfo); + if ( ret ) + goto err; + + ret =3D make_psci_node(kinfo->fdt); + if ( ret ) + goto err; + + ret =3D make_cpus_node(d, kinfo->fdt); + if ( ret ) + goto err; + + ret =3D make_memory_node(d, kinfo->fdt, addrcells, sizecells, &kinfo->= mem); + if ( ret ) + goto err; + + ret =3D make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, + &kinfo->shm_mem); + if ( ret ) + goto err; + + /* + * domain_handle_dtb_bootmodule has to be called before the rest of + * the device tree is generated because it depends on the value of + * the field phandle_gic. + */ + if ( kinfo->dtb_bootmodule ) + { + ret =3D domain_handle_dtb_bootmodule(d, kinfo); + if ( ret ) + goto err; + } + + ret =3D make_gic_domU_node(kinfo); + if ( ret ) + goto err; + + ret =3D make_timer_node(kinfo); + if ( ret ) + goto err; + + if ( kinfo->vpl011 ) + { + ret =3D -EINVAL; +#ifdef CONFIG_SBSA_VUART_CONSOLE + ret =3D make_vpl011_uart_node(kinfo); +#endif + if ( ret ) + goto err; + } + + if ( kinfo->dom0less_feature & DOM0LESS_ENHANCED_NO_XS ) + { + ret =3D make_hypervisor_node(d, kinfo, addrcells, sizecells); + if ( ret ) + goto err; + } + + ret =3D fdt_end_node(kinfo->fdt); + if ( ret < 0 ) + goto err; + + ret =3D fdt_finish(kinfo->fdt); + if ( ret < 0 ) + goto err; + + return 0; + + err: + printk("Device tree generation failed (%d).\n", ret); + xfree(kinfo->fdt); + + return -EINVAL; +} + +static unsigned long __init domain_p2m_pages(unsigned long maxmem_kb, + unsigned int smp_cpus) +{ + /* + * Keep in sync with libxl__get_required_paging_memory(). + * 256 pages (1MB) per vcpu, plus 1 page per MiB of RAM for the P2M ma= p, + * plus 128 pages to cover extended regions. + */ + unsigned long memkb =3D 4 * (256 * smp_cpus + (maxmem_kb / 1024) + 128= ); + + BUILD_BUG_ON(PAGE_SIZE !=3D SZ_4K); + + return DIV_ROUND_UP(memkb, 1024) << (20 - PAGE_SHIFT); +} + +static int __init alloc_xenstore_evtchn(struct domain *d) +{ + evtchn_alloc_unbound_t alloc; + int rc; + + alloc.dom =3D d->domain_id; + alloc.remote_dom =3D hardware_domain->domain_id; + rc =3D evtchn_alloc_unbound(&alloc, 0); + if ( rc ) + { + printk("Failed allocating event channel for domain\n"); + return rc; + } + + d->arch.hvm.params[HVM_PARAM_STORE_EVTCHN] =3D alloc.port; + + return 0; +} + +static int __init construct_domU(struct domain *d, + const struct dt_device_node *node) +{ + struct kernel_info kinfo =3D {}; + const char *dom0less_enhanced; + int rc; + u64 mem; + u32 p2m_mem_mb; + unsigned long p2m_pages; + + rc =3D dt_property_read_u64(node, "memory", &mem); + if ( !rc ) + { + printk("Error building DomU: cannot read \"memory\" property\n"); + return -EINVAL; + } + kinfo.unassigned_mem =3D (paddr_t)mem * SZ_1K; + + rc =3D dt_property_read_u32(node, "xen,domain-p2m-mem-mb", &p2m_mem_mb= ); + /* If xen,domain-p2m-mem-mb is not specified, use the default value. */ + p2m_pages =3D rc ? + p2m_mem_mb << (20 - PAGE_SHIFT) : + domain_p2m_pages(mem, d->max_vcpus); + + spin_lock(&d->arch.paging.lock); + rc =3D p2m_set_allocation(d, p2m_pages, NULL); + spin_unlock(&d->arch.paging.lock); + if ( rc !=3D 0 ) + return rc; + + printk("*** LOADING DOMU cpus=3D%u memory=3D%#"PRIx64"KB ***\n", + d->max_vcpus, mem); + + kinfo.vpl011 =3D dt_property_read_bool(node, "vpl011"); + + rc =3D dt_property_read_string(node, "xen,enhanced", &dom0less_enhance= d); + if ( rc =3D=3D -EILSEQ || + rc =3D=3D -ENODATA || + (rc =3D=3D 0 && !strcmp(dom0less_enhanced, "enabled")) ) + { + if ( hardware_domain ) + kinfo.dom0less_feature =3D DOM0LESS_ENHANCED; + else + panic("At the moment, Xenstore support requires dom0 to be pre= sent\n"); + } + else if ( rc =3D=3D 0 && !strcmp(dom0less_enhanced, "no-xenstore") ) + kinfo.dom0less_feature =3D DOM0LESS_ENHANCED_NO_XS; + + if ( vcpu_create(d, 0) =3D=3D NULL ) + return -ENOMEM; + + d->max_pages =3D ((paddr_t)mem * SZ_1K) >> PAGE_SHIFT; + + kinfo.d =3D d; + + rc =3D kernel_probe(&kinfo, node); + if ( rc < 0 ) + return rc; + +#ifdef CONFIG_ARM_64 + /* type must be set before allocate memory */ + d->arch.type =3D kinfo.type; +#endif + if ( !dt_find_property(node, "xen,static-mem", NULL) ) + allocate_memory(d, &kinfo); + else if ( !is_domain_direct_mapped(d) ) + allocate_static_memory(d, &kinfo, node); + else + assign_static_memory_11(d, &kinfo, node); + +#ifdef CONFIG_STATIC_SHM + rc =3D process_shm(d, &kinfo, node); + if ( rc < 0 ) + return rc; +#endif + + /* + * Base address and irq number are needed when creating vpl011 device + * tree node in prepare_dtb_domU, so initialization on related variabl= es + * shall be done first. + */ + if ( kinfo.vpl011 ) + { + rc =3D domain_vpl011_init(d, NULL); + if ( rc < 0 ) + return rc; + } + + rc =3D prepare_dtb_domU(d, &kinfo); + if ( rc < 0 ) + return rc; + + rc =3D construct_domain(d, &kinfo); + if ( rc < 0 ) + return rc; + + if ( kinfo.dom0less_feature & DOM0LESS_XENSTORE ) + { + ASSERT(hardware_domain); + rc =3D alloc_xenstore_evtchn(d); + if ( rc < 0 ) + return rc; + d->arch.hvm.params[HVM_PARAM_STORE_PFN] =3D ~0ULL; + } + + return rc; +} + +void __init create_domUs(void) +{ + struct dt_device_node *node; + const struct dt_device_node *cpupool_node, + *chosen =3D dt_find_node_by_path("/chosen"= ); + + BUG_ON(chosen =3D=3D NULL); + dt_for_each_child_node(chosen, node) + { + struct domain *d; + struct xen_domctl_createdomain d_cfg =3D { + .arch.gic_version =3D XEN_DOMCTL_CONFIG_GIC_NATIVE, + .flags =3D XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap, + /* + * The default of 1023 should be sufficient for guests because + * on ARM we don't bind physical interrupts to event channels. + * The only use of the evtchn port is inter-domain communicati= ons. + * 1023 is also the default value used in libxl. + */ + .max_evtchn_port =3D 1023, + .max_grant_frames =3D -1, + .max_maptrack_frames =3D -1, + .grant_opts =3D XEN_DOMCTL_GRANT_version(opt_gnttab_max_versio= n), + }; + unsigned int flags =3D 0U; + uint32_t val; + int rc; + + if ( !dt_device_is_compatible(node, "xen,domain") ) + continue; + + if ( (max_init_domid + 1) >=3D DOMID_FIRST_RESERVED ) + panic("No more domain IDs available\n"); + + if ( dt_find_property(node, "xen,static-mem", NULL) ) + flags |=3D CDF_staticmem; + + if ( dt_property_read_bool(node, "direct-map") ) + { + if ( !(flags & CDF_staticmem) ) + panic("direct-map is not valid for domain %s without stati= c allocation.\n", + dt_node_name(node)); + + flags |=3D CDF_directmap; + } + + if ( !dt_property_read_u32(node, "cpus", &d_cfg.max_vcpus) ) + panic("Missing property 'cpus' for domain %s\n", + dt_node_name(node)); + + if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") = && + iommu_enabled ) + d_cfg.flags |=3D XEN_DOMCTL_CDF_iommu; + + if ( !dt_property_read_u32(node, "nr_spis", &d_cfg.arch.nr_spis) ) + { + int vpl011_virq =3D GUEST_VPL011_SPI; + + d_cfg.arch.nr_spis =3D gic_number_lines() - 32; + + /* + * The VPL011 virq is GUEST_VPL011_SPI, unless direct-map is + * set, in which case it'll match the hardware. + * + * Since the domain is not yet created, we can't use + * d->arch.vpl011.irq. So the logic to find the vIRQ has to + * be hardcoded. + * The logic here shall be consistent with the one in + * domain_vpl011_init(). + */ + if ( flags & CDF_directmap ) + { + vpl011_virq =3D serial_irq(SERHND_DTUART); + if ( vpl011_virq < 0 ) + panic("Error getting IRQ number for this serial port %= d\n", + SERHND_DTUART); + } + + /* + * vpl011 uses one emulated SPI. If vpl011 is requested, make + * sure that we allocate enough SPIs for it. + */ + if ( dt_property_read_bool(node, "vpl011") ) + d_cfg.arch.nr_spis =3D MAX(d_cfg.arch.nr_spis, + vpl011_virq - 32 + 1); + } + + /* Get the optional property domain-cpupool */ + cpupool_node =3D dt_parse_phandle(node, "domain-cpupool", 0); + if ( cpupool_node ) + { + int pool_id =3D btcpupools_get_domain_pool_id(cpupool_node); + if ( pool_id < 0 ) + panic("Error getting cpupool id from domain-cpupool (%d)\n= ", + pool_id); + d_cfg.cpupool_id =3D pool_id; + } + + if ( dt_property_read_u32(node, "max_grant_version", &val) ) + d_cfg.grant_opts =3D XEN_DOMCTL_GRANT_version(val); + + if ( dt_property_read_u32(node, "max_grant_frames", &val) ) + { + if ( val > INT32_MAX ) + panic("max_grant_frames (%"PRIu32") overflow\n", val); + d_cfg.max_grant_frames =3D val; + } + + if ( dt_property_read_u32(node, "max_maptrack_frames", &val) ) + { + if ( val > INT32_MAX ) + panic("max_maptrack_frames (%"PRIu32") overflow\n", val); + d_cfg.max_maptrack_frames =3D val; + } + + if ( dt_get_property(node, "sve", &val) ) + { +#ifdef CONFIG_ARM64_SVE + unsigned int sve_vl_bits; + bool ret =3D false; + + if ( !val ) + { + /* Property found with no value, means max HW VL supported= */ + ret =3D sve_domctl_vl_param(-1, &sve_vl_bits); + } + else + { + if ( dt_property_read_u32(node, "sve", &val) ) + ret =3D sve_domctl_vl_param(val, &sve_vl_bits); + else + panic("Error reading 'sve' property\n"); + } + + if ( ret ) + d_cfg.arch.sve_vl =3D sve_encode_vl(sve_vl_bits); + else + panic("SVE vector length error\n"); +#else + panic("'sve' property found, but CONFIG_ARM64_SVE not selected= \n"); +#endif + } + + /* + * The variable max_init_domid is initialized with zero, so here i= t's + * very important to use the pre-increment operator to call + * domain_create() with a domid > 0. (domid =3D=3D 0 is reserved f= or Dom0) + */ + d =3D domain_create(++max_init_domid, &d_cfg, flags); + if ( IS_ERR(d) ) + panic("Error creating domain %s (rc =3D %ld)\n", + dt_node_name(node), PTR_ERR(d)); + + d->is_console =3D true; + dt_device_set_used_by(node, d->domain_id); + + rc =3D construct_domU(d, node); + if ( rc ) + panic("Could not set up domain %s (rc =3D %d)\n", + dt_node_name(node), rc); + } +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index f69f238ccea4..a0d656b33629 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include =20 @@ -117,7 +118,7 @@ struct vcpu *__init alloc_dom0_vcpu0(struct domain *dom= 0) return vcpu_create(dom0, 0); } =20 -static unsigned int __init get_allocation_size(paddr_t size) +unsigned int __init get_allocation_size(paddr_t size) { /* * get_order_from_bytes returns the order greater than or equal to @@ -413,113 +414,6 @@ static void __init allocate_memory_11(struct domain *= d, } } =20 -static bool __init allocate_bank_memory(struct domain *d, - struct kernel_info *kinfo, - gfn_t sgfn, - paddr_t tot_size) -{ - int res; - struct page_info *pg; - struct membank *bank; - unsigned int max_order =3D ~0; - - /* - * allocate_bank_memory can be called with a tot_size of zero for - * the second memory bank. It is not an error and we can safely - * avoid creating a zero-size memory bank. - */ - if ( tot_size =3D=3D 0 ) - return true; - - bank =3D &kinfo->mem.bank[kinfo->mem.nr_banks]; - bank->start =3D gfn_to_gaddr(sgfn); - bank->size =3D tot_size; - - while ( tot_size > 0 ) - { - unsigned int order =3D get_allocation_size(tot_size); - - order =3D min(max_order, order); - - pg =3D alloc_domheap_pages(d, order, 0); - if ( !pg ) - { - /* - * If we can't allocate one page, then it is unlikely to - * succeed in the next iteration. So bail out. - */ - if ( !order ) - return false; - - /* - * If we can't allocate memory with order, then it is - * unlikely to succeed in the next iteration. - * Record the order - 1 to avoid re-trying. - */ - max_order =3D order - 1; - continue; - } - - res =3D guest_physmap_add_page(d, sgfn, page_to_mfn(pg), order); - if ( res ) - { - dprintk(XENLOG_ERR, "Failed map pages to DOMU: %d", res); - return false; - } - - sgfn =3D gfn_add(sgfn, 1UL << order); - tot_size -=3D (1ULL << (PAGE_SHIFT + order)); - } - - kinfo->mem.nr_banks++; - kinfo->unassigned_mem -=3D bank->size; - - return true; -} - -static void __init allocate_memory(struct domain *d, struct kernel_info *k= info) -{ - unsigned int i; - paddr_t bank_size; - - printk(XENLOG_INFO "Allocating mappings totalling %ldMB for %pd:\n", - /* Don't want format this as PRIpaddr (16 digit hex) */ - (unsigned long)(kinfo->unassigned_mem >> 20), d); - - kinfo->mem.nr_banks =3D 0; - bank_size =3D MIN(GUEST_RAM0_SIZE, kinfo->unassigned_mem); - if ( !allocate_bank_memory(d, kinfo, gaddr_to_gfn(GUEST_RAM0_BASE), - bank_size) ) - goto fail; - - bank_size =3D MIN(GUEST_RAM1_SIZE, kinfo->unassigned_mem); - if ( !allocate_bank_memory(d, kinfo, gaddr_to_gfn(GUEST_RAM1_BASE), - bank_size) ) - goto fail; - - if ( kinfo->unassigned_mem ) - goto fail; - - for( i =3D 0; i < kinfo->mem.nr_banks; i++ ) - { - printk(XENLOG_INFO "%pd BANK[%d] %#"PRIpaddr"-%#"PRIpaddr" (%ldMB)= \n", - d, - i, - kinfo->mem.bank[i].start, - kinfo->mem.bank[i].start + kinfo->mem.bank[i].size, - /* Don't want format this as PRIpaddr (16 digit hex) */ - (unsigned long)(kinfo->mem.bank[i].size >> 20)); - } - - return; - -fail: - panic("Failed to allocate requested domain memory." - /* Don't want format this as PRIpaddr (16 digit hex) */ - " %ldKB unallocated. Fix the VMs configurations.\n", - (unsigned long)kinfo->unassigned_mem >> 10); -} - #ifdef CONFIG_STATIC_MEMORY static bool __init append_static_memory_to_bank(struct domain *d, struct membank *bank, @@ -599,9 +493,8 @@ static int __init parse_static_mem_prop(const struct dt= _device_node *node, } =20 /* Allocate memory from static memory as RAM for one specific domain d. */ -static void __init allocate_static_memory(struct domain *d, - struct kernel_info *kinfo, - const struct dt_device_node *nod= e) +void __init allocate_static_memory(struct domain *d, struct kernel_info *k= info, + const struct dt_device_node *node) { u32 addr_cells, size_cells, reg_cells; unsigned int nr_banks, gbank, bank =3D 0; @@ -705,9 +598,8 @@ static void __init allocate_static_memory(struct domain= *d, * The static memory will be directly mapped in the guest(Guest Physical * Address =3D=3D Physical Address). */ -static void __init assign_static_memory_11(struct domain *d, - struct kernel_info *kinfo, - const struct dt_device_node *no= de) +void __init assign_static_memory_11(struct domain *d, struct kernel_info *= kinfo, + const struct dt_device_node *node) { u32 addr_cells, size_cells, reg_cells; unsigned int nr_banks, bank =3D 0; @@ -941,8 +833,8 @@ static int __init append_shm_bank_to_domain(struct kern= el_info *kinfo, return 0; } =20 -static int __init process_shm(struct domain *d, struct kernel_info *kinfo, - const struct dt_device_node *node) +int __init process_shm(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node) { struct dt_device_node *shm_node; =20 @@ -1047,20 +939,6 @@ static int __init process_shm(struct domain *d, struc= t kernel_info *kinfo, return 0; } #endif /* CONFIG_STATIC_SHM */ -#else -static void __init allocate_static_memory(struct domain *d, - struct kernel_info *kinfo, - const struct dt_device_node *nod= e) -{ - ASSERT_UNREACHABLE(); -} - -static void __init assign_static_memory_11(struct domain *d, - struct kernel_info *kinfo, - const struct dt_device_node *no= de) -{ - ASSERT_UNREACHABLE(); -} #endif =20 /* @@ -1264,17 +1142,10 @@ static int __init write_properties(struct domain *d= , struct kernel_info *kinfo, return 0; } =20 -/* - * Helper to write an interrupts with the GIC format - * This code is assuming the irq is an PPI. - */ - -typedef __be32 gic_interrupt_t[3]; - -static void __init set_interrupt(gic_interrupt_t interrupt, - unsigned int irq, - unsigned int cpumask, - unsigned int level) +void __init set_interrupt(gic_interrupt_t interrupt, + unsigned int irq, + unsigned int cpumask, + unsigned int level) { __be32 *cells =3D interrupt; bool is_ppi =3D !!(irq < 32); @@ -1319,8 +1190,7 @@ static int __init fdt_property_interrupts(const struc= t kernel_info *kinfo, * unit (which contains the physical address) with name to generate a * node name. */ -static int __init domain_fdt_begin_node(void *fdt, const char *name, - uint64_t unit) +int __init domain_fdt_begin_node(void *fdt, const char *name, uint64_t uni= t) { /* * The size of the buffer to hold the longest possible string (i.e. @@ -1344,10 +1214,10 @@ static int __init domain_fdt_begin_node(void *fdt, = const char *name, return fdt_begin_node(fdt, buf); } =20 -static int __init make_memory_node(const struct domain *d, - void *fdt, - int addrcells, int sizecells, - struct meminfo *mem) +int __init make_memory_node(const struct domain *d, + void *fdt, + int addrcells, int sizecells, + struct meminfo *mem) { unsigned int i; int res, reg_size =3D addrcells + sizecells; @@ -1483,10 +1353,10 @@ static int __init make_shm_memory_node(const struct= domain *d, } #endif =20 -static int __init make_resv_memory_node(const struct domain *d, - void *fdt, - int addrcells, int sizecells, - const struct meminfo *mem) +int __init make_resv_memory_node(const struct domain *d, + void *fdt, + int addrcells, int sizecells, + const struct meminfo *mem) { int res =3D 0; /* Placeholder for reserved-memory\0 */ @@ -1819,9 +1689,9 @@ static int __init find_domU_holes(const struct kernel= _info *kinfo, return res; } =20 -static int __init make_hypervisor_node(struct domain *d, - const struct kernel_info *kinfo, - int addrcells, int sizecells) +int __init make_hypervisor_node(struct domain *d, + const struct kernel_info *kinfo, + int addrcells, int sizecells) { const char compat[] =3D "xen,xen-" XEN_VERSION_STRING "\0" @@ -1938,7 +1808,7 @@ static int __init make_hypervisor_node(struct domain = *d, return res; } =20 -static int __init make_psci_node(void *fdt) +int __init make_psci_node(void *fdt) { int res; const char compat[] =3D @@ -1974,7 +1844,7 @@ static int __init make_psci_node(void *fdt) return res; } =20 -static int __init make_cpus_node(const struct domain *d, void *fdt) +int __init make_cpus_node(const struct domain *d, void *fdt) { int res; const struct dt_device_node *cpus =3D dt_find_node_by_path("/cpus"); @@ -2172,7 +2042,7 @@ static int __init make_gic_node(const struct domain *= d, void *fdt, return res; } =20 -static int __init make_timer_node(const struct kernel_info *kinfo) +int __init make_timer_node(const struct kernel_info *kinfo) { void *fdt =3D kinfo->fdt; static const struct dt_device_match timer_ids[] __initconst =3D @@ -2490,743 +2360,134 @@ static int __init handle_node(struct domain *d, s= truct kernel_info *kinfo, return res; } =20 -#ifdef CONFIG_VGICV2 -static int __init make_gicv2_domU_node(struct kernel_info *kinfo) +static int __init prepare_dtb_hwdom(struct domain *d, struct kernel_info *= kinfo) { - void *fdt =3D kinfo->fdt; - int res =3D 0; - __be32 reg[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) * 2]; - __be32 *cells; - const struct domain *d =3D kinfo->d; - - res =3D domain_fdt_begin_node(fdt, "interrupt-controller", - vgic_dist_base(&d->arch.vgic)); - if ( res ) - return res; - - res =3D fdt_property_cell(fdt, "#address-cells", 0); - if ( res ) - return res; + const p2m_type_t default_p2mt =3D p2m_mmio_direct_c; + const void *fdt; + int new_size; + int ret; =20 - res =3D fdt_property_cell(fdt, "#interrupt-cells", 3); - if ( res ) - return res; + ASSERT(dt_host && (dt_host->sibling =3D=3D NULL)); =20 - res =3D fdt_property(fdt, "interrupt-controller", NULL, 0); - if ( res ) - return res; + kinfo->phandle_gic =3D dt_interrupt_controller->phandle; + fdt =3D device_tree_flattened; =20 - res =3D fdt_property_string(fdt, "compatible", "arm,gic-400"); - if ( res ) - return res; + new_size =3D fdt_totalsize(fdt) + DOM0_FDT_EXTRA_SIZE; + kinfo->fdt =3D xmalloc_bytes(new_size); + if ( kinfo->fdt =3D=3D NULL ) + return -ENOMEM; =20 - cells =3D ®[0]; - dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_C= ELLS, - vgic_dist_base(&d->arch.vgic), GUEST_GICD_SIZE); - dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_C= ELLS, - vgic_cpu_base(&d->arch.vgic), GUEST_GICC_SIZE); + ret =3D fdt_create(kinfo->fdt, new_size); + if ( ret < 0 ) + goto err; =20 - res =3D fdt_property(fdt, "reg", reg, sizeof(reg)); - if (res) - return res; + fdt_finish_reservemap(kinfo->fdt); =20 - res =3D fdt_property_cell(fdt, "linux,phandle", kinfo->phandle_gic); - if (res) - return res; + ret =3D handle_node(d, kinfo, dt_host, default_p2mt); + if ( ret ) + goto err; =20 - res =3D fdt_property_cell(fdt, "phandle", kinfo->phandle_gic); - if (res) - return res; + ret =3D fdt_finish(kinfo->fdt); + if ( ret < 0 ) + goto err; =20 - res =3D fdt_end_node(fdt); + return 0; =20 - return res; + err: + printk("Device tree generation failed (%d).\n", ret); + xfree(kinfo->fdt); + return -EINVAL; } -#endif =20 -#ifdef CONFIG_GICV3 -static int __init make_gicv3_domU_node(struct kernel_info *kinfo) +static void __init dtb_load(struct kernel_info *kinfo) { - void *fdt =3D kinfo->fdt; - int res =3D 0; - __be32 *reg, *cells; - const struct domain *d =3D kinfo->d; - unsigned int i, len =3D 0; - - res =3D domain_fdt_begin_node(fdt, "interrupt-controller", - vgic_dist_base(&d->arch.vgic)); - if ( res ) - return res; - - res =3D fdt_property_cell(fdt, "#address-cells", 0); - if ( res ) - return res; - - res =3D fdt_property_cell(fdt, "#interrupt-cells", 3); - if ( res ) - return res; - - res =3D fdt_property(fdt, "interrupt-controller", NULL, 0); - if ( res ) - return res; - - res =3D fdt_property_string(fdt, "compatible", "arm,gic-v3"); - if ( res ) - return res; - - /* reg specifies all re-distributors and Distributor. */ - len =3D (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) * - (d->arch.vgic.nr_regions + 1) * sizeof(__be32); - reg =3D xmalloc_bytes(len); - if ( reg =3D=3D NULL ) - return -ENOMEM; - cells =3D reg; - - dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_C= ELLS, - vgic_dist_base(&d->arch.vgic), GUEST_GICV3_GICD_SIZ= E); - - for ( i =3D 0; i < d->arch.vgic.nr_regions; i++ ) - dt_child_set_range(&cells, - GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS, - d->arch.vgic.rdist_regions[i].base, - d->arch.vgic.rdist_regions[i].size); - - res =3D fdt_property(fdt, "reg", reg, len); - xfree(reg); - if (res) - return res; - - res =3D fdt_property_cell(fdt, "linux,phandle", kinfo->phandle_gic); - if (res) - return res; - - res =3D fdt_property_cell(fdt, "phandle", kinfo->phandle_gic); - if (res) - return res; + unsigned long left; =20 - res =3D fdt_end_node(fdt); + printk("Loading %pd DTB to 0x%"PRIpaddr"-0x%"PRIpaddr"\n", + kinfo->d, kinfo->dtb_paddr, + kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt)); =20 - return res; -} -#endif + left =3D copy_to_guest_phys_flush_dcache(kinfo->d, kinfo->dtb_paddr, + kinfo->fdt, + fdt_totalsize(kinfo->fdt)); =20 -static int __init make_gic_domU_node(struct kernel_info *kinfo) -{ - switch ( kinfo->d->arch.vgic.version ) - { -#ifdef CONFIG_GICV3 - case GIC_V3: - return make_gicv3_domU_node(kinfo); -#endif -#ifdef CONFIG_VGICV2 - case GIC_V2: - return make_gicv2_domU_node(kinfo); -#endif - default: - panic("Unsupported GIC version\n"); - } + if ( left !=3D 0 ) + panic("Unable to copy the DTB to %pd memory (left =3D %lu bytes)\n= ", + kinfo->d, left); + xfree(kinfo->fdt); } =20 -#ifdef CONFIG_SBSA_VUART_CONSOLE -static int __init make_vpl011_uart_node(struct kernel_info *kinfo) +static void __init initrd_load(struct kernel_info *kinfo) { - void *fdt =3D kinfo->fdt; + const struct bootmodule *mod =3D kinfo->initrd_bootmodule; + paddr_t load_addr =3D kinfo->initrd_paddr; + paddr_t paddr, len; + int node; int res; - gic_interrupt_t intr; - __be32 reg[GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS]; - __be32 *cells; - struct domain *d =3D kinfo->d; - - res =3D domain_fdt_begin_node(fdt, "sbsa-uart", d->arch.vpl011.base_ad= dr); - if ( res ) - return res; + __be32 val[2]; + __be32 *cellp; + void __iomem *initrd; =20 - res =3D fdt_property_string(fdt, "compatible", "arm,sbsa-uart"); - if ( res ) - return res; + if ( !mod || !mod->size ) + return; =20 - cells =3D ®[0]; - dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, - GUEST_ROOT_SIZE_CELLS, d->arch.vpl011.base_addr, - GUEST_PL011_SIZE); + paddr =3D mod->start; + len =3D mod->size; =20 - res =3D fdt_property(fdt, "reg", reg, sizeof(reg)); - if ( res ) - return res; + printk("Loading %pd initrd from %"PRIpaddr" to 0x%"PRIpaddr"-0x%"PRIpa= ddr"\n", + kinfo->d, paddr, load_addr, load_addr + len); =20 - set_interrupt(intr, d->arch.vpl011.virq, 0xf, DT_IRQ_TYPE_LEVEL_HIGH); + /* Fix up linux,initrd-start and linux,initrd-end in /chosen */ + node =3D fdt_path_offset(kinfo->fdt, "/chosen"); + if ( node < 0 ) + panic("Cannot find the /chosen node\n"); =20 - res =3D fdt_property(fdt, "interrupts", intr, sizeof (intr)); + cellp =3D (__be32 *)val; + dt_set_cell(&cellp, ARRAY_SIZE(val), load_addr); + res =3D fdt_setprop_inplace(kinfo->fdt, node, "linux,initrd-start", + val, sizeof(val)); if ( res ) - return res; + panic("Cannot fix up \"linux,initrd-start\" property\n"); =20 - res =3D fdt_property_cell(fdt, "interrupt-parent", - kinfo->phandle_gic); + cellp =3D (__be32 *)val; + dt_set_cell(&cellp, ARRAY_SIZE(val), load_addr + len); + res =3D fdt_setprop_inplace(kinfo->fdt, node, "linux,initrd-end", + val, sizeof(val)); if ( res ) - return res; + panic("Cannot fix up \"linux,initrd-end\" property\n"); =20 - /* Use a default baud rate of 115200. */ - fdt_property_u32(fdt, "current-speed", 115200); + initrd =3D ioremap_wc(paddr, len); + if ( !initrd ) + panic("Unable to map the hwdom initrd\n"); =20 - res =3D fdt_end_node(fdt); - if ( res ) - return res; + res =3D copy_to_guest_phys_flush_dcache(kinfo->d, load_addr, + initrd, len); + if ( res !=3D 0 ) + panic("Unable to copy the initrd in the hwdom memory\n"); =20 - return 0; + iounmap(initrd); } -#endif =20 /* - * Scan device tree properties for passthrough specific information. - * Returns < 0 on error - * 0 on success + * Allocate the event channel PPIs and setup the HVM_PARAM_CALLBACK_IRQ. + * The allocated IRQ will be found in d->arch.evtchn_irq. + * + * Note that this should only be called once all PPIs used by the + * hardware domain have been registered. */ -static int __init handle_passthrough_prop(struct kernel_info *kinfo, - const struct fdt_property *xen_r= eg, - const struct fdt_property *xen_p= ath, - bool xen_force, - uint32_t address_cells, uint32_t= size_cells) +void __init evtchn_allocate(struct domain *d) { - const __be32 *cell; - unsigned int i, len; - struct dt_device_node *node; int res; - paddr_t mstart, size, gstart; - - /* xen,reg specifies where to map the MMIO region */ - cell =3D (const __be32 *)xen_reg->data; - len =3D fdt32_to_cpu(xen_reg->len) / ((address_cells * 2 + size_cells)= * - sizeof(uint32_t)); + u64 val; =20 - for ( i =3D 0; i < len; i++ ) - { - device_tree_get_reg(&cell, address_cells, size_cells, - &mstart, &size); - gstart =3D dt_next_cell(address_cells, &cell); + res =3D vgic_allocate_ppi(d); + if ( res < 0 ) + panic("Unable to allocate a PPI for the event channel interrupt\n"= ); =20 - if ( gstart & ~PAGE_MASK || mstart & ~PAGE_MASK || size & ~PAGE_MA= SK ) - { - printk(XENLOG_ERR - "DomU passthrough config has not page aligned addresse= s/sizes\n"); - return -EINVAL; - } + d->arch.evtchn_irq =3D res; =20 - res =3D iomem_permit_access(kinfo->d, paddr_to_pfn(mstart), - paddr_to_pfn(PAGE_ALIGN(mstart + size - = 1))); - if ( res ) - { - printk(XENLOG_ERR "Unable to permit to dom%d access to" - " 0x%"PRIpaddr" - 0x%"PRIpaddr"\n", - kinfo->d->domain_id, - mstart & PAGE_MASK, PAGE_ALIGN(mstart + size) - 1); - return res; - } - - res =3D map_regions_p2mt(kinfo->d, - gaddr_to_gfn(gstart), - PFN_DOWN(size), - maddr_to_mfn(mstart), - p2m_mmio_direct_dev); - if ( res < 0 ) - { - printk(XENLOG_ERR - "Failed to map %"PRIpaddr" to the guest at%"PRIpaddr"\n= ", - mstart, gstart); - return -EFAULT; - } - } - - /* - * If xen_force, we let the user assign a MMIO region with no - * associated path. - */ - if ( xen_path =3D=3D NULL ) - return xen_force ? 0 : -EINVAL; - - /* - * xen,path specifies the corresponding node in the host DT. - * Both interrupt mappings and IOMMU settings are based on it, - * as they are done based on the corresponding host DT node. - */ - node =3D dt_find_node_by_path(xen_path->data); - if ( node =3D=3D NULL ) - { - printk(XENLOG_ERR "Couldn't find node %s in host_dt!\n", - (char *)xen_path->data); - return -EINVAL; - } - - res =3D map_device_irqs_to_domain(kinfo->d, node, true, NULL); - if ( res < 0 ) - return res; - - res =3D iommu_add_dt_device(node); - if ( res < 0 ) - return res; - - /* If xen_force, we allow assignment of devices without IOMMU protecti= on. */ - if ( xen_force && !dt_device_is_protected(node) ) - return 0; - - return iommu_assign_dt_device(kinfo->d, node); -} - -static int __init handle_prop_pfdt(struct kernel_info *kinfo, - const void *pfdt, int nodeoff, - uint32_t address_cells, uint32_t size_c= ells, - bool scan_passthrough_prop) -{ - void *fdt =3D kinfo->fdt; - int propoff, nameoff, res; - const struct fdt_property *prop, *xen_reg =3D NULL, *xen_path =3D NULL; - const char *name; - bool found, xen_force =3D false; - - for ( propoff =3D fdt_first_property_offset(pfdt, nodeoff); - propoff >=3D 0; - propoff =3D fdt_next_property_offset(pfdt, propoff) ) - { - if ( !(prop =3D fdt_get_property_by_offset(pfdt, propoff, NULL)) ) - return -FDT_ERR_INTERNAL; - - found =3D false; - nameoff =3D fdt32_to_cpu(prop->nameoff); - name =3D fdt_string(pfdt, nameoff); - - if ( scan_passthrough_prop ) - { - if ( dt_prop_cmp("xen,reg", name) =3D=3D 0 ) - { - xen_reg =3D prop; - found =3D true; - } - else if ( dt_prop_cmp("xen,path", name) =3D=3D 0 ) - { - xen_path =3D prop; - found =3D true; - } - else if ( dt_prop_cmp("xen,force-assign-without-iommu", - name) =3D=3D 0 ) - { - xen_force =3D true; - found =3D true; - } - } - - /* - * Copy properties other than the ones above: xen,reg, xen,path, - * and xen,force-assign-without-iommu. - */ - if ( !found ) - { - res =3D fdt_property(fdt, name, prop->data, fdt32_to_cpu(prop-= >len)); - if ( res ) - return res; - } - } - - /* - * Only handle passthrough properties if both xen,reg and xen,path - * are present, or if xen,force-assign-without-iommu is specified. - */ - if ( xen_reg !=3D NULL && (xen_path !=3D NULL || xen_force) ) - { - res =3D handle_passthrough_prop(kinfo, xen_reg, xen_path, xen_forc= e, - address_cells, size_cells); - if ( res < 0 ) - { - printk(XENLOG_ERR "Failed to assign device to %pd\n", kinfo->d= ); - return res; - } - } - else if ( (xen_path && !xen_reg) || (xen_reg && !xen_path && !xen_forc= e) ) - { - printk(XENLOG_ERR "xen,reg or xen,path missing for %pd\n", - kinfo->d); - return -EINVAL; - } - - /* FDT_ERR_NOTFOUND =3D> There is no more properties for this node */ - return ( propoff !=3D -FDT_ERR_NOTFOUND ) ? propoff : 0; -} - -static int __init scan_pfdt_node(struct kernel_info *kinfo, const void *pf= dt, - int nodeoff, - uint32_t address_cells, uint32_t size_cel= ls, - bool scan_passthrough_prop) -{ - int rc =3D 0; - void *fdt =3D kinfo->fdt; - int node_next; - - rc =3D fdt_begin_node(fdt, fdt_get_name(pfdt, nodeoff, NULL)); - if ( rc ) - return rc; - - rc =3D handle_prop_pfdt(kinfo, pfdt, nodeoff, address_cells, size_cell= s, - scan_passthrough_prop); - if ( rc ) - return rc; - - address_cells =3D device_tree_get_u32(pfdt, nodeoff, "#address-cells", - DT_ROOT_NODE_ADDR_CELLS_DEFAULT); - size_cells =3D device_tree_get_u32(pfdt, nodeoff, "#size-cells", - DT_ROOT_NODE_SIZE_CELLS_DEFAULT); - - node_next =3D fdt_first_subnode(pfdt, nodeoff); - while ( node_next > 0 ) - { - scan_pfdt_node(kinfo, pfdt, node_next, address_cells, size_cells, - scan_passthrough_prop); - node_next =3D fdt_next_subnode(pfdt, node_next); - } - - return fdt_end_node(fdt); -} - -static int __init check_partial_fdt(void *pfdt, size_t size) -{ - int res; - - if ( fdt_magic(pfdt) !=3D FDT_MAGIC ) - { - dprintk(XENLOG_ERR, "Partial FDT is not a valid Flat Device Tree"); - return -EINVAL; - } - - res =3D fdt_check_header(pfdt); - if ( res ) - { - dprintk(XENLOG_ERR, "Failed to check the partial FDT (%d)", res); - return -EINVAL; - } - - if ( fdt_totalsize(pfdt) > size ) - { - dprintk(XENLOG_ERR, "Partial FDT totalsize is too big"); - return -EINVAL; - } - - return 0; -} - -static int __init domain_handle_dtb_bootmodule(struct domain *d, - struct kernel_info *kinfo) -{ - void *pfdt; - int res, node_next; - - pfdt =3D ioremap_cache(kinfo->dtb_bootmodule->start, - kinfo->dtb_bootmodule->size); - if ( pfdt =3D=3D NULL ) - return -EFAULT; - - res =3D check_partial_fdt(pfdt, kinfo->dtb_bootmodule->size); - if ( res < 0 ) - goto out; - - for ( node_next =3D fdt_first_subnode(pfdt, 0);=20 - node_next > 0; - node_next =3D fdt_next_subnode(pfdt, node_next) ) - { - const char *name =3D fdt_get_name(pfdt, node_next, NULL); - - if ( name =3D=3D NULL ) - continue; - - /* - * Only scan /gic /aliases /passthrough, ignore the rest. - * They don't have to be parsed in order. - * - * Take the GIC phandle value from the special /gic node in the - * DTB fragment. - */ - if ( dt_node_cmp(name, "gic") =3D=3D 0 ) - { - kinfo->phandle_gic =3D fdt_get_phandle(pfdt, node_next); - continue; - } - - if ( dt_node_cmp(name, "aliases") =3D=3D 0 ) - { - res =3D scan_pfdt_node(kinfo, pfdt, node_next, - DT_ROOT_NODE_ADDR_CELLS_DEFAULT, - DT_ROOT_NODE_SIZE_CELLS_DEFAULT, - false); - if ( res ) - goto out; - continue; - } - if ( dt_node_cmp(name, "passthrough") =3D=3D 0 ) - { - res =3D scan_pfdt_node(kinfo, pfdt, node_next, - DT_ROOT_NODE_ADDR_CELLS_DEFAULT, - DT_ROOT_NODE_SIZE_CELLS_DEFAULT, - true); - if ( res ) - goto out; - continue; - } - } - - out: - iounmap(pfdt); - - return res; -} - -/* - * The max size for DT is 2MB. However, the generated DT is small (not inc= luding - * domU passthrough DT nodes whose size we account separately), 4KB are en= ough - * for now, but we might have to increase it in the future. - */ -#define DOMU_DTB_SIZE 4096 -static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *k= info) -{ - int addrcells, sizecells; - int ret, fdt_size =3D DOMU_DTB_SIZE; - - kinfo->phandle_gic =3D GUEST_PHANDLE_GIC; - kinfo->gnttab_start =3D GUEST_GNTTAB_BASE; - kinfo->gnttab_size =3D GUEST_GNTTAB_SIZE; - - addrcells =3D GUEST_ROOT_ADDRESS_CELLS; - sizecells =3D GUEST_ROOT_SIZE_CELLS; - - /* Account for domU passthrough DT size */ - if ( kinfo->dtb_bootmodule ) - fdt_size +=3D kinfo->dtb_bootmodule->size; - - /* Cap to max DT size if needed */ - fdt_size =3D min(fdt_size, SZ_2M); - - kinfo->fdt =3D xmalloc_bytes(fdt_size); - if ( kinfo->fdt =3D=3D NULL ) - return -ENOMEM; - - ret =3D fdt_create(kinfo->fdt, fdt_size); - if ( ret < 0 ) - goto err; - - ret =3D fdt_finish_reservemap(kinfo->fdt); - if ( ret < 0 ) - goto err; - - ret =3D fdt_begin_node(kinfo->fdt, ""); - if ( ret < 0 ) - goto err; - - ret =3D fdt_property_cell(kinfo->fdt, "#address-cells", addrcells); - if ( ret ) - goto err; - - ret =3D fdt_property_cell(kinfo->fdt, "#size-cells", sizecells); - if ( ret ) - goto err; - - ret =3D make_chosen_node(kinfo); - if ( ret ) - goto err; - - ret =3D make_psci_node(kinfo->fdt); - if ( ret ) - goto err; - - ret =3D make_cpus_node(d, kinfo->fdt); - if ( ret ) - goto err; - - ret =3D make_memory_node(d, kinfo->fdt, addrcells, sizecells, &kinfo->= mem); - if ( ret ) - goto err; - - ret =3D make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, - &kinfo->shm_mem); - if ( ret ) - goto err; - - /* - * domain_handle_dtb_bootmodule has to be called before the rest of - * the device tree is generated because it depends on the value of - * the field phandle_gic. - */ - if ( kinfo->dtb_bootmodule ) - { - ret =3D domain_handle_dtb_bootmodule(d, kinfo); - if ( ret ) - goto err; - } - - ret =3D make_gic_domU_node(kinfo); - if ( ret ) - goto err; - - ret =3D make_timer_node(kinfo); - if ( ret ) - goto err; - - if ( kinfo->vpl011 ) - { - ret =3D -EINVAL; -#ifdef CONFIG_SBSA_VUART_CONSOLE - ret =3D make_vpl011_uart_node(kinfo); -#endif - if ( ret ) - goto err; - } - - if ( kinfo->dom0less_feature & DOM0LESS_ENHANCED_NO_XS ) - { - ret =3D make_hypervisor_node(d, kinfo, addrcells, sizecells); - if ( ret ) - goto err; - } - - ret =3D fdt_end_node(kinfo->fdt); - if ( ret < 0 ) - goto err; - - ret =3D fdt_finish(kinfo->fdt); - if ( ret < 0 ) - goto err; - - return 0; - - err: - printk("Device tree generation failed (%d).\n", ret); - xfree(kinfo->fdt); - - return -EINVAL; -} - -static int __init prepare_dtb_hwdom(struct domain *d, struct kernel_info *= kinfo) -{ - const p2m_type_t default_p2mt =3D p2m_mmio_direct_c; - const void *fdt; - int new_size; - int ret; - - ASSERT(dt_host && (dt_host->sibling =3D=3D NULL)); - - kinfo->phandle_gic =3D dt_interrupt_controller->phandle; - fdt =3D device_tree_flattened; - - new_size =3D fdt_totalsize(fdt) + DOM0_FDT_EXTRA_SIZE; - kinfo->fdt =3D xmalloc_bytes(new_size); - if ( kinfo->fdt =3D=3D NULL ) - return -ENOMEM; - - ret =3D fdt_create(kinfo->fdt, new_size); - if ( ret < 0 ) - goto err; - - fdt_finish_reservemap(kinfo->fdt); - - ret =3D handle_node(d, kinfo, dt_host, default_p2mt); - if ( ret ) - goto err; - - ret =3D fdt_finish(kinfo->fdt); - if ( ret < 0 ) - goto err; - - return 0; - - err: - printk("Device tree generation failed (%d).\n", ret); - xfree(kinfo->fdt); - return -EINVAL; -} - -static void __init dtb_load(struct kernel_info *kinfo) -{ - unsigned long left; - - printk("Loading %pd DTB to 0x%"PRIpaddr"-0x%"PRIpaddr"\n", - kinfo->d, kinfo->dtb_paddr, - kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt)); - - left =3D copy_to_guest_phys_flush_dcache(kinfo->d, kinfo->dtb_paddr, - kinfo->fdt, - fdt_totalsize(kinfo->fdt)); - - if ( left !=3D 0 ) - panic("Unable to copy the DTB to %pd memory (left =3D %lu bytes)\n= ", - kinfo->d, left); - xfree(kinfo->fdt); -} - -static void __init initrd_load(struct kernel_info *kinfo) -{ - const struct bootmodule *mod =3D kinfo->initrd_bootmodule; - paddr_t load_addr =3D kinfo->initrd_paddr; - paddr_t paddr, len; - int node; - int res; - __be32 val[2]; - __be32 *cellp; - void __iomem *initrd; - - if ( !mod || !mod->size ) - return; - - paddr =3D mod->start; - len =3D mod->size; - - printk("Loading %pd initrd from %"PRIpaddr" to 0x%"PRIpaddr"-0x%"PRIpa= ddr"\n", - kinfo->d, paddr, load_addr, load_addr + len); - - /* Fix up linux,initrd-start and linux,initrd-end in /chosen */ - node =3D fdt_path_offset(kinfo->fdt, "/chosen"); - if ( node < 0 ) - panic("Cannot find the /chosen node\n"); - - cellp =3D (__be32 *)val; - dt_set_cell(&cellp, ARRAY_SIZE(val), load_addr); - res =3D fdt_setprop_inplace(kinfo->fdt, node, "linux,initrd-start", - val, sizeof(val)); - if ( res ) - panic("Cannot fix up \"linux,initrd-start\" property\n"); - - cellp =3D (__be32 *)val; - dt_set_cell(&cellp, ARRAY_SIZE(val), load_addr + len); - res =3D fdt_setprop_inplace(kinfo->fdt, node, "linux,initrd-end", - val, sizeof(val)); - if ( res ) - panic("Cannot fix up \"linux,initrd-end\" property\n"); - - initrd =3D ioremap_wc(paddr, len); - if ( !initrd ) - panic("Unable to map the hwdom initrd\n"); - - res =3D copy_to_guest_phys_flush_dcache(kinfo->d, load_addr, - initrd, len); - if ( res !=3D 0 ) - panic("Unable to copy the initrd in the hwdom memory\n"); - - iounmap(initrd); -} - -/* - * Allocate the event channel PPIs and setup the HVM_PARAM_CALLBACK_IRQ. - * The allocated IRQ will be found in d->arch.evtchn_irq. - * - * Note that this should only be called once all PPIs used by the - * hardware domain have been registered. - */ -void __init evtchn_allocate(struct domain *d) -{ - int res; - u64 val; - - res =3D vgic_allocate_ppi(d); - if ( res < 0 ) - panic("Unable to allocate a PPI for the event channel interrupt\n"= ); - - d->arch.evtchn_irq =3D res; - - printk("Allocating PPI %u for event channel interrupt\n", - d->arch.evtchn_irq); + printk("Allocating PPI %u for event channel interrupt\n", + d->arch.evtchn_irq); =20 /* Set the value of domain param HVM_PARAM_CALLBACK_IRQ */ val =3D MASK_INSR(HVM_PARAM_CALLBACK_TYPE_PPI, @@ -3409,22 +2670,7 @@ static void __init find_gnttab_region(struct domain = *d, kinfo->gnttab_start, kinfo->gnttab_start + kinfo->gnttab_size); } =20 -static unsigned long __init domain_p2m_pages(unsigned long maxmem_kb, - unsigned int smp_cpus) -{ - /* - * Keep in sync with libxl__get_required_paging_memory(). - * 256 pages (1MB) per vcpu, plus 1 page per MiB of RAM for the P2M ma= p, - * plus 128 pages to cover extended regions. - */ - unsigned long memkb =3D 4 * (256 * smp_cpus + (maxmem_kb / 1024) + 128= ); - - BUILD_BUG_ON(PAGE_SIZE !=3D SZ_4K); - - return DIV_ROUND_UP(memkb, 1024) << (20 - PAGE_SHIFT); -} - -static int __init construct_domain(struct domain *d, struct kernel_info *k= info) +int __init construct_domain(struct domain *d, struct kernel_info *kinfo) { unsigned int i; struct vcpu *v =3D d->vcpu[0]; @@ -3515,296 +2761,6 @@ static int __init construct_domain(struct domain *d= , struct kernel_info *kinfo) return 0; } =20 -static int __init alloc_xenstore_evtchn(struct domain *d) -{ - evtchn_alloc_unbound_t alloc; - int rc; - - alloc.dom =3D d->domain_id; - alloc.remote_dom =3D hardware_domain->domain_id; - rc =3D evtchn_alloc_unbound(&alloc, 0); - if ( rc ) - { - printk("Failed allocating event channel for domain\n"); - return rc; - } - - d->arch.hvm.params[HVM_PARAM_STORE_EVTCHN] =3D alloc.port; - - return 0; -} - -static int __init construct_domU(struct domain *d, - const struct dt_device_node *node) -{ - struct kernel_info kinfo =3D {}; - const char *dom0less_enhanced; - int rc; - u64 mem; - u32 p2m_mem_mb; - unsigned long p2m_pages; - - rc =3D dt_property_read_u64(node, "memory", &mem); - if ( !rc ) - { - printk("Error building DomU: cannot read \"memory\" property\n"); - return -EINVAL; - } - kinfo.unassigned_mem =3D (paddr_t)mem * SZ_1K; - - rc =3D dt_property_read_u32(node, "xen,domain-p2m-mem-mb", &p2m_mem_mb= ); - /* If xen,domain-p2m-mem-mb is not specified, use the default value. */ - p2m_pages =3D rc ? - p2m_mem_mb << (20 - PAGE_SHIFT) : - domain_p2m_pages(mem, d->max_vcpus); - - spin_lock(&d->arch.paging.lock); - rc =3D p2m_set_allocation(d, p2m_pages, NULL); - spin_unlock(&d->arch.paging.lock); - if ( rc !=3D 0 ) - return rc; - - printk("*** LOADING DOMU cpus=3D%u memory=3D%#"PRIx64"KB ***\n", - d->max_vcpus, mem); - - kinfo.vpl011 =3D dt_property_read_bool(node, "vpl011"); - - rc =3D dt_property_read_string(node, "xen,enhanced", &dom0less_enhance= d); - if ( rc =3D=3D -EILSEQ || - rc =3D=3D -ENODATA || - (rc =3D=3D 0 && !strcmp(dom0less_enhanced, "enabled")) ) - { - if ( hardware_domain ) - kinfo.dom0less_feature =3D DOM0LESS_ENHANCED; - else - panic("At the moment, Xenstore support requires dom0 to be pre= sent\n"); - } - else if ( rc =3D=3D 0 && !strcmp(dom0less_enhanced, "no-xenstore") ) - kinfo.dom0less_feature =3D DOM0LESS_ENHANCED_NO_XS; - - if ( vcpu_create(d, 0) =3D=3D NULL ) - return -ENOMEM; - - d->max_pages =3D ((paddr_t)mem * SZ_1K) >> PAGE_SHIFT; - - kinfo.d =3D d; - - rc =3D kernel_probe(&kinfo, node); - if ( rc < 0 ) - return rc; - -#ifdef CONFIG_ARM_64 - /* type must be set before allocate memory */ - d->arch.type =3D kinfo.type; -#endif - if ( !dt_find_property(node, "xen,static-mem", NULL) ) - allocate_memory(d, &kinfo); - else if ( !is_domain_direct_mapped(d) ) - allocate_static_memory(d, &kinfo, node); - else - assign_static_memory_11(d, &kinfo, node); - -#ifdef CONFIG_STATIC_SHM - rc =3D process_shm(d, &kinfo, node); - if ( rc < 0 ) - return rc; -#endif - - /* - * Base address and irq number are needed when creating vpl011 device - * tree node in prepare_dtb_domU, so initialization on related variabl= es - * shall be done first. - */ - if ( kinfo.vpl011 ) - { - rc =3D domain_vpl011_init(d, NULL); - if ( rc < 0 ) - return rc; - } - - rc =3D prepare_dtb_domU(d, &kinfo); - if ( rc < 0 ) - return rc; - - rc =3D construct_domain(d, &kinfo); - if ( rc < 0 ) - return rc; - - if ( kinfo.dom0less_feature & DOM0LESS_XENSTORE ) - { - ASSERT(hardware_domain); - rc =3D alloc_xenstore_evtchn(d); - if ( rc < 0 ) - return rc; - d->arch.hvm.params[HVM_PARAM_STORE_PFN] =3D ~0ULL; - } - - return rc; -} - -void __init create_domUs(void) -{ - struct dt_device_node *node; - const struct dt_device_node *cpupool_node, - *chosen =3D dt_find_node_by_path("/chosen"= ); - - BUG_ON(chosen =3D=3D NULL); - dt_for_each_child_node(chosen, node) - { - struct domain *d; - struct xen_domctl_createdomain d_cfg =3D { - .arch.gic_version =3D XEN_DOMCTL_CONFIG_GIC_NATIVE, - .flags =3D XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap, - /* - * The default of 1023 should be sufficient for guests because - * on ARM we don't bind physical interrupts to event channels. - * The only use of the evtchn port is inter-domain communicati= ons. - * 1023 is also the default value used in libxl. - */ - .max_evtchn_port =3D 1023, - .max_grant_frames =3D -1, - .max_maptrack_frames =3D -1, - .grant_opts =3D XEN_DOMCTL_GRANT_version(opt_gnttab_max_versio= n), - }; - unsigned int flags =3D 0U; - uint32_t val; - int rc; - - if ( !dt_device_is_compatible(node, "xen,domain") ) - continue; - - if ( (max_init_domid + 1) >=3D DOMID_FIRST_RESERVED ) - panic("No more domain IDs available\n"); - - if ( dt_find_property(node, "xen,static-mem", NULL) ) - flags |=3D CDF_staticmem; - - if ( dt_property_read_bool(node, "direct-map") ) - { - if ( !(flags & CDF_staticmem) ) - panic("direct-map is not valid for domain %s without stati= c allocation.\n", - dt_node_name(node)); - - flags |=3D CDF_directmap; - } - - if ( !dt_property_read_u32(node, "cpus", &d_cfg.max_vcpus) ) - panic("Missing property 'cpus' for domain %s\n", - dt_node_name(node)); - - if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") = && - iommu_enabled ) - d_cfg.flags |=3D XEN_DOMCTL_CDF_iommu; - - if ( !dt_property_read_u32(node, "nr_spis", &d_cfg.arch.nr_spis) ) - { - int vpl011_virq =3D GUEST_VPL011_SPI; - - d_cfg.arch.nr_spis =3D gic_number_lines() - 32; - - /* - * The VPL011 virq is GUEST_VPL011_SPI, unless direct-map is - * set, in which case it'll match the hardware. - * - * Since the domain is not yet created, we can't use - * d->arch.vpl011.irq. So the logic to find the vIRQ has to - * be hardcoded. - * The logic here shall be consistent with the one in - * domain_vpl011_init(). - */ - if ( flags & CDF_directmap ) - { - vpl011_virq =3D serial_irq(SERHND_DTUART); - if ( vpl011_virq < 0 ) - panic("Error getting IRQ number for this serial port %= d\n", - SERHND_DTUART); - } - - /* - * vpl011 uses one emulated SPI. If vpl011 is requested, make - * sure that we allocate enough SPIs for it. - */ - if ( dt_property_read_bool(node, "vpl011") ) - d_cfg.arch.nr_spis =3D MAX(d_cfg.arch.nr_spis, - vpl011_virq - 32 + 1); - } - - /* Get the optional property domain-cpupool */ - cpupool_node =3D dt_parse_phandle(node, "domain-cpupool", 0); - if ( cpupool_node ) - { - int pool_id =3D btcpupools_get_domain_pool_id(cpupool_node); - if ( pool_id < 0 ) - panic("Error getting cpupool id from domain-cpupool (%d)\n= ", - pool_id); - d_cfg.cpupool_id =3D pool_id; - } - - if ( dt_property_read_u32(node, "max_grant_version", &val) ) - d_cfg.grant_opts =3D XEN_DOMCTL_GRANT_version(val); - - if ( dt_property_read_u32(node, "max_grant_frames", &val) ) - { - if ( val > INT32_MAX ) - panic("max_grant_frames (%"PRIu32") overflow\n", val); - d_cfg.max_grant_frames =3D val; - } - - if ( dt_property_read_u32(node, "max_maptrack_frames", &val) ) - { - if ( val > INT32_MAX ) - panic("max_maptrack_frames (%"PRIu32") overflow\n", val); - d_cfg.max_maptrack_frames =3D val; - } - - if ( dt_get_property(node, "sve", &val) ) - { -#ifdef CONFIG_ARM64_SVE - unsigned int sve_vl_bits; - bool ret =3D false; - - if ( !val ) - { - /* Property found with no value, means max HW VL supported= */ - ret =3D sve_domctl_vl_param(-1, &sve_vl_bits); - } - else - { - if ( dt_property_read_u32(node, "sve", &val) ) - ret =3D sve_domctl_vl_param(val, &sve_vl_bits); - else - panic("Error reading 'sve' property\n"); - } - - if ( ret ) - d_cfg.arch.sve_vl =3D sve_encode_vl(sve_vl_bits); - else - panic("SVE vector length error\n"); -#else - panic("'sve' property found, but CONFIG_ARM64_SVE not selected= \n"); -#endif - } - - /* - * The variable max_init_domid is initialized with zero, so here i= t's - * very important to use the pre-increment operator to call - * domain_create() with a domid > 0. (domid =3D=3D 0 is reserved f= or Dom0) - */ - d =3D domain_create(++max_init_domid, &d_cfg, flags); - if ( IS_ERR(d) ) - panic("Error creating domain %s (rc =3D %ld)\n", - dt_node_name(node), PTR_ERR(d)); - - d->is_console =3D true; - dt_device_set_used_by(node, d->domain_id); - - rc =3D construct_domU(d, node); - if ( rc ) - panic("Could not set up domain %s (rc =3D %d)\n", - dt_node_name(node), rc); - } -} - static int __init construct_dom0(struct domain *d) { struct kernel_info kinfo =3D {}; diff --git a/xen/arch/arm/include/asm/dom0less-build.h b/xen/arch/arm/inclu= de/asm/dom0less-build.h new file mode 100644 index 000000000000..0d28fa1bee46 --- /dev/null +++ b/xen/arch/arm/include/asm/dom0less-build.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * xen/arch/arm/include/asm/dom0less-build.h + * + * Copyright (C) 2023 Arm Ltd. + */ + +#ifndef __ARM_DOM0LESS_BUILD_H_ +#define __ARM_DOM0LESS_BUILD_H_ + +#include + +void create_domUs(void); +bool is_dom0less_mode(void); + +#endif /* __ARM_DOM0LESS_BUILD_H_ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End:b + */ diff --git a/xen/arch/arm/include/asm/domain_build.h b/xen/arch/arm/include= /asm/domain_build.h index b9329c9ee032..d95cf376048f 100644 --- a/xen/arch/arm/include/asm/domain_build.h +++ b/xen/arch/arm/include/asm/domain_build.h @@ -4,9 +4,45 @@ #include #include =20 +typedef __be32 gic_interrupt_t[3]; + +int construct_domain(struct domain *d, struct kernel_info *kinfo); +int domain_fdt_begin_node(void *fdt, const char *name, uint64_t unit); +int make_resv_memory_node(const struct domain *d, void *fdt, int addrcells, + int sizecells, const struct meminfo *mem); int make_chosen_node(const struct kernel_info *kinfo); +int make_cpus_node(const struct domain *d, void *fdt); +int make_hypervisor_node(struct domain *d, const struct kernel_info *kinfo, + int addrcells, int sizecells); +int make_memory_node(const struct domain *d, void *fdt, int addrcells, + int sizecells, struct meminfo *mem); +int make_psci_node(void *fdt); +int make_timer_node(const struct kernel_info *kinfo); void evtchn_allocate(struct domain *d); =20 +unsigned int get_allocation_size(paddr_t size); + +/* + * handle_device_interrupts retrieves the interrupts configuration from + * a device tree node and maps those interrupts to the target domain. + * + * Returns: + * < 0 error + * 0 success + */ +int handle_device_interrupts(struct domain *d, struct dt_device_node *dev, + bool need_mapping); + +/* + * Helper to write an interrupts with the GIC format + * This code is assuming the irq is an PPI. + */ +void set_interrupt(gic_interrupt_t interrupt, unsigned int irq, + unsigned int cpumask, unsigned int level); + +int process_shm(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node); + #ifndef CONFIG_ACPI static inline int prepare_acpi(struct domain *d, struct kernel_info *kinfo) { @@ -17,6 +53,28 @@ static inline int prepare_acpi(struct domain *d, struct = kernel_info *kinfo) #else int prepare_acpi(struct domain *d, struct kernel_info *kinfo); #endif + +#ifdef CONFIG_STATIC_MEMORY +void allocate_static_memory(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node); +void assign_static_memory_11(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node); +#else +static inline void allocate_static_memory(struct domain *d, + struct kernel_info *kinfo, + const struct dt_device_node *nod= e) +{ + ASSERT_UNREACHABLE(); +} + +static inline void assign_static_memory_11(struct domain *d, + struct kernel_info *kinfo, + const struct dt_device_node *no= de) +{ + ASSERT_UNREACHABLE(); +} +#endif + #endif =20 /* diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/se= tup.h index b8866c20f462..cd4c7815790b 100644 --- a/xen/arch/arm/include/asm/setup.h +++ b/xen/arch/arm/include/asm/setup.h @@ -135,7 +135,6 @@ void acpi_create_efi_mmap_table(struct domain *d, =20 int acpi_make_efi_nodes(void *fdt, struct membank tbl_add[]); =20 -void create_domUs(void); void create_dom0(void); void alloc_static_evtchn(void); =20 diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index db748839d383..db0299d540dc 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -1042,38 +1043,6 @@ static void __init setup_mm(void) } #endif =20 -static bool __init is_dom0less_mode(void) -{ - struct bootmodules *mods =3D &bootinfo.modules; - struct bootmodule *mod; - unsigned int i; - bool dom0found =3D false; - bool domUfound =3D false; - - /* Look into the bootmodules */ - for ( i =3D 0 ; i < mods->nr_mods ; i++ ) - { - mod =3D &mods->module[i]; - /* Find if dom0 and domU kernels are present */ - if ( mod->kind =3D=3D BOOTMOD_KERNEL ) - { - if ( mod->domU =3D=3D false ) - { - dom0found =3D true; - break; - } - else - domUfound =3D true; - } - } - - /* - * If there is no dom0 kernel but at least one domU, then we are in - * dom0less mode - */ - return ( !dom0found && domUfound ); -} - size_t __read_mostly dcache_line_bytes; =20 /* C entry point for boot CPU */ --=20 2.34.1 From nobody Thu May 16 00:42:45 2024 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; 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; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1695823341662388.4498579815514; Wed, 27 Sep 2023 07:02:21 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.608951.947810 (Exim 4.92) (envelope-from ) id 1qlV6t-0007TN-Sc; Wed, 27 Sep 2023 14:01:51 +0000 Received: by outflank-mailman (output) from mailman id 608951.947810; Wed, 27 Sep 2023 14:01:51 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1qlV6t-0007S9-O3; Wed, 27 Sep 2023 14:01:51 +0000 Received: by outflank-mailman (input) for mailman id 608951; Wed, 27 Sep 2023 14:01:50 +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 1qlV6s-0006eS-7S for xen-devel@lists.xenproject.org; Wed, 27 Sep 2023 14:01:50 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 65fd9b5f-5d3e-11ee-878a-cb3800f73035; Wed, 27 Sep 2023 16:01:47 +0200 (CEST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 5377CDA7; Wed, 27 Sep 2023 07:02:25 -0700 (PDT) Received: from e125770.cambridge.arm.com (e125770.arm.com [10.1.199.1]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 43FE43F59C; Wed, 27 Sep 2023 07:01:46 -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: 65fd9b5f-5d3e-11ee-878a-cb3800f73035 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: wei.chen@arm.com, Stefano Stabellini , Julien Grall , Bertrand Marquis , Volodymyr Babchuk Subject: [PATCH v2 4/5] xen/arm: Move static memory build code in separate modules Date: Wed, 27 Sep 2023 15:01:32 +0100 Message-Id: <20230927140133.631192-5-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230927140133.631192-1-luca.fancellu@arm.com> References: <20230927140133.631192-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1695823342432100001 Content-Type: text/plain; charset="utf-8" Move static memory and static shared memory code in separate modules so that they are included only when the corresponding feature is enabled, doing that we modularise the features and we remove some ifdefs from the code to improve readability. Move process_shm_node function from bootfdt module and make it externally visible. A static inline helper called process_shm_chosen is introduced, it will call the process_shm function for the '/chosen' node, and will be used by the function construct_dom0 instead of using directly process_shm, allowing some #ifdef to be removed. No functional changes are intended. Signed-off-by: Luca Fancellu --- xen/arch/arm/Makefile | 2 + xen/arch/arm/bootfdt.c | 161 +----- xen/arch/arm/dom0less-build.c | 4 +- xen/arch/arm/domain_build.c | 614 +--------------------- xen/arch/arm/include/asm/dom0less-build.h | 2 - xen/arch/arm/include/asm/domain_build.h | 24 - xen/arch/arm/include/asm/static-memory.h | 50 ++ xen/arch/arm/include/asm/static-shmem.h | 72 +++ xen/arch/arm/setup.c | 25 +- xen/arch/arm/static-memory.c | 294 +++++++++++ xen/arch/arm/static-shmem.c | 515 ++++++++++++++++++ 11 files changed, 939 insertions(+), 824 deletions(-) create mode 100644 xen/arch/arm/include/asm/static-memory.h create mode 100644 xen/arch/arm/include/asm/static-shmem.h create mode 100644 xen/arch/arm/static-memory.c create mode 100644 xen/arch/arm/static-shmem.c diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 70dd7201ef30..89ef0c9075b5 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -50,6 +50,8 @@ obj-y +=3D setup.o obj-y +=3D shutdown.o obj-y +=3D smp.o obj-y +=3D smpboot.o +obj-$(CONFIG_STATIC_MEMORY) +=3D static-memory.init.o +obj-$(CONFIG_STATIC_SHM) +=3D static-shmem.init.o obj-y +=3D sysctl.o obj-y +=3D time.o obj-y +=3D traps.o diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c index 2673ad17a1e1..fcf851b4c99b 100644 --- a/xen/arch/arm/bootfdt.c +++ b/xen/arch/arm/bootfdt.c @@ -15,6 +15,7 @@ #include #include #include +#include =20 static bool __init device_tree_node_matches(const void *fdt, int node, const char *match) @@ -402,166 +403,6 @@ static int __init process_domain_node(const void *fdt= , int node, MEMBANK_STATIC_DOMAIN); } =20 -#ifdef CONFIG_STATIC_SHM -static int __init process_shm_node(const void *fdt, int node, - uint32_t address_cells, uint32_t size_c= ells) -{ - const struct fdt_property *prop, *prop_id, *prop_role; - const __be32 *cell; - paddr_t paddr, gaddr, size; - struct meminfo *mem =3D &bootinfo.reserved_mem; - unsigned int i; - int len; - bool owner =3D false; - const char *shm_id; - - if ( address_cells < 1 || size_cells < 1 ) - { - printk("fdt: invalid #address-cells or #size-cells for static shar= ed memory node.\n"); - return -EINVAL; - } - - /* - * "xen,shm-id" property holds an arbitrary string with a strict limit - * on the number of characters, MAX_SHM_ID_LENGTH - */ - prop_id =3D fdt_get_property(fdt, node, "xen,shm-id", NULL); - if ( !prop_id ) - return -ENOENT; - shm_id =3D (const char *)prop_id->data; - if ( strnlen(shm_id, MAX_SHM_ID_LENGTH) =3D=3D MAX_SHM_ID_LENGTH ) - { - printk("fdt: invalid xen,shm-id %s, it must be limited to %u chara= cters\n", - shm_id, MAX_SHM_ID_LENGTH); - return -EINVAL; - } - - /* - * "role" property is optional and if it is defined explicitly, - * it must be either `owner` or `borrower`. - */ - prop_role =3D fdt_get_property(fdt, node, "role", NULL); - if ( prop_role ) - { - if ( !strcmp(prop_role->data, "owner") ) - owner =3D true; - else if ( strcmp(prop_role->data, "borrower") ) - { - printk("fdt: invalid `role` property for static shared memory = node.\n"); - return -EINVAL; - } - } - - /* - * xen,shared-mem =3D ; - * Memory region starting from physical address #paddr of #size shall - * be mapped to guest physical address #gaddr as static shared memory - * region. - */ - prop =3D fdt_get_property(fdt, node, "xen,shared-mem", &len); - if ( !prop ) - return -ENOENT; - - if ( len !=3D dt_cells_to_size(address_cells + size_cells + address_ce= lls) ) - { - if ( len =3D=3D dt_cells_to_size(size_cells + address_cells) ) - printk("fdt: host physical address must be chosen by users at = the moment.\n"); - - printk("fdt: invalid `xen,shared-mem` property.\n"); - return -EINVAL; - } - - cell =3D (const __be32 *)prop->data; - device_tree_get_reg(&cell, address_cells, address_cells, &paddr, &gadd= r); - size =3D dt_next_cell(size_cells, &cell); - - if ( !size ) - { - printk("fdt: the size for static shared memory region can not be z= ero\n"); - return -EINVAL; - } - - for ( i =3D 0; i < mem->nr_banks; i++ ) - { - /* - * Meet the following check: - * 1) The shm ID matches and the region exactly match - * 2) The shm ID doesn't match and the region doesn't overlap - * with an existing one - */ - if ( paddr =3D=3D mem->bank[i].start && size =3D=3D mem->bank[i].s= ize ) - { - if ( strncmp(shm_id, mem->bank[i].shm_id, MAX_SHM_ID_LENGTH) = =3D=3D 0 ) - break; - else - { - printk("fdt: xen,shm-id %s does not match for all the node= s using the same region.\n", - shm_id); - return -EINVAL; - } - } - else - { - paddr_t end =3D paddr + size; - paddr_t bank_end =3D mem->bank[i].start + mem->bank[i].size; - - if ( (end <=3D paddr) || (bank_end <=3D mem->bank[i].start) ) - { - printk("fdt: static shared memory region %s overflow\n", s= hm_id); - return -EINVAL; - } - - if ( check_reserved_regions_overlap(paddr, size) ) - return -EINVAL; - else - { - if ( strcmp(shm_id, mem->bank[i].shm_id) !=3D 0 ) - continue; - else - { - printk("fdt: different shared memory region could not = share the same shm ID %s\n", - shm_id); - return -EINVAL; - } - } - } - } - - if ( i =3D=3D mem->nr_banks ) - { - if ( i < NR_MEM_BANKS ) - { - /* Static shared memory shall be reserved from any other use. = */ - safe_strcpy(mem->bank[mem->nr_banks].shm_id, shm_id); - mem->bank[mem->nr_banks].start =3D paddr; - mem->bank[mem->nr_banks].size =3D size; - mem->bank[mem->nr_banks].type =3D MEMBANK_STATIC_DOMAIN; - mem->nr_banks++; - } - else - { - printk("Warning: Max number of supported memory regions reache= d.\n"); - return -ENOSPC; - } - } - /* - * keep a count of the number of borrowers, which later may be used - * to calculate the reference count. - */ - if ( !owner ) - mem->bank[i].nr_shm_borrowers++; - - return 0; -} -#else -static int __init process_shm_node(const void *fdt, int node, - uint32_t address_cells, uint32_t size_c= ells) -{ - printk("CONFIG_STATIC_SHM must be enabled for parsing static shared me= mory nodes\n"); - return -EINVAL; -} -#endif - static int __init early_scan_node(const void *fdt, int node, const char *name, int depth, u32 address_cells, u32 size_cells, diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c index dc9c90cf00a7..a401501fd70c 100644 --- a/xen/arch/arm/dom0less-build.c +++ b/xen/arch/arm/dom0less-build.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include =20 bool __init is_dom0less_mode(void) { @@ -875,11 +877,9 @@ static int __init construct_domU(struct domain *d, else assign_static_memory_11(d, &kinfo, node); =20 -#ifdef CONFIG_STATIC_SHM rc =3D process_shm(d, &kinfo, node); if ( rc < 0 ) return rc; -#endif =20 /* * Base address and irq number are needed when creating vpl011 device diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index a0d656b33629..9ffe498a434c 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -30,6 +30,7 @@ #include #include #include +#include #include =20 #include @@ -414,533 +415,6 @@ static void __init allocate_memory_11(struct domain *= d, } } =20 -#ifdef CONFIG_STATIC_MEMORY -static bool __init append_static_memory_to_bank(struct domain *d, - struct membank *bank, - mfn_t smfn, - paddr_t size) -{ - int res; - unsigned int nr_pages =3D PFN_DOWN(size); - gfn_t sgfn; - - /* - * For direct-mapped domain, the GFN match the MFN. - * Otherwise, this is inferred on what has already been allocated - * in the bank. - */ - if ( !is_domain_direct_mapped(d) ) - sgfn =3D gaddr_to_gfn(bank->start + bank->size); - else - sgfn =3D gaddr_to_gfn(mfn_to_maddr(smfn)); - - res =3D guest_physmap_add_pages(d, sgfn, smfn, nr_pages); - if ( res ) - { - dprintk(XENLOG_ERR, "Failed to map pages to DOMU: %d", res); - return false; - } - - bank->size =3D bank->size + size; - - return true; -} - -static mfn_t __init acquire_static_memory_bank(struct domain *d, - const __be32 **cell, - u32 addr_cells, u32 size_ce= lls, - paddr_t *pbase, paddr_t *ps= ize) -{ - mfn_t smfn; - int res; - - device_tree_get_reg(cell, addr_cells, size_cells, pbase, psize); - ASSERT(IS_ALIGNED(*pbase, PAGE_SIZE) && IS_ALIGNED(*psize, PAGE_SIZE)); - if ( PFN_DOWN(*psize) > UINT_MAX ) - { - printk(XENLOG_ERR "%pd: static memory size too large: %#"PRIpaddr, - d, *psize); - return INVALID_MFN; - } - - smfn =3D maddr_to_mfn(*pbase); - res =3D acquire_domstatic_pages(d, smfn, PFN_DOWN(*psize), 0); - if ( res ) - { - printk(XENLOG_ERR - "%pd: failed to acquire static memory: %d.\n", d, res); - return INVALID_MFN; - } - - return smfn; -} - -static int __init parse_static_mem_prop(const struct dt_device_node *node, - u32 *addr_cells, u32 *size_cells, - int *length, const __be32 **cell) -{ - const struct dt_property *prop; - - prop =3D dt_find_property(node, "xen,static-mem", NULL); - - *addr_cells =3D dt_n_addr_cells(node); - *size_cells =3D dt_n_size_cells(node); - - *cell =3D (const __be32 *)prop->value; - *length =3D prop->length; - - return 0; -} - -/* Allocate memory from static memory as RAM for one specific domain d. */ -void __init allocate_static_memory(struct domain *d, struct kernel_info *k= info, - const struct dt_device_node *node) -{ - u32 addr_cells, size_cells, reg_cells; - unsigned int nr_banks, gbank, bank =3D 0; - const uint64_t rambase[] =3D GUEST_RAM_BANK_BASES; - const uint64_t ramsize[] =3D GUEST_RAM_BANK_SIZES; - const __be32 *cell; - u64 tot_size =3D 0; - paddr_t pbase, psize, gsize; - mfn_t smfn; - int length; - - if ( parse_static_mem_prop(node, &addr_cells, &size_cells, &length, &c= ell) ) - goto fail; - reg_cells =3D addr_cells + size_cells; - - /* - * The static memory will be mapped in the guest at the usual guest me= mory - * addresses (GUEST_RAM0_BASE, GUEST_RAM1_BASE) defined by - * xen/include/public/arch-arm.h. - */ - gbank =3D 0; - gsize =3D ramsize[gbank]; - kinfo->mem.bank[gbank].start =3D rambase[gbank]; - nr_banks =3D length / (reg_cells * sizeof (u32)); - - for ( ; bank < nr_banks; bank++ ) - { - smfn =3D acquire_static_memory_bank(d, &cell, addr_cells, size_cel= ls, - &pbase, &psize); - if ( mfn_eq(smfn, INVALID_MFN) ) - goto fail; - - printk(XENLOG_INFO "%pd: STATIC BANK[%u] %#"PRIpaddr"-%#"PRIpaddr"= \n", - d, bank, pbase, pbase + psize); - - while ( 1 ) - { - /* Map as much as possible the static range to the guest bank = */ - if ( !append_static_memory_to_bank(d, &kinfo->mem.bank[gbank],= smfn, - min(psize, gsize)) ) - goto fail; - - /* - * The current physical bank is fully mapped. - * Handle the next physical bank. - */ - if ( gsize >=3D psize ) - { - gsize =3D gsize - psize; - break; - } - /* - * When current guest bank is not enough to map, exhaust - * the current one and seek to the next. - * Before seeking to the next, check if we still have available - * guest bank. - */ - else if ( (gbank + 1) >=3D GUEST_RAM_BANKS ) - { - printk(XENLOG_ERR "Exhausted all possible guest banks.\n"); - goto fail; - } - else - { - psize =3D psize - gsize; - smfn =3D mfn_add(smfn, gsize >> PAGE_SHIFT); - /* Update to the next guest bank. */ - gbank++; - gsize =3D ramsize[gbank]; - kinfo->mem.bank[gbank].start =3D rambase[gbank]; - } - } - - tot_size +=3D psize; - } - - kinfo->mem.nr_banks =3D ++gbank; - - kinfo->unassigned_mem -=3D tot_size; - /* - * The property 'memory' should match the amount of memory given to the - * guest. - * Currently, it is only possible to either acquire static memory or l= et - * Xen allocate. *Mixing* is not supported. - */ - if ( kinfo->unassigned_mem ) - { - printk(XENLOG_ERR - "Size of \"memory\" property doesn't match up with the sum-= up of \"xen,static-mem\". Unsupported configuration.\n"); - goto fail; - } - - return; - - fail: - panic("Failed to allocate requested static memory for domain %pd.\n", = d); -} - -/* - * Allocate static memory as RAM for one specific domain d. - * The static memory will be directly mapped in the guest(Guest Physical - * Address =3D=3D Physical Address). - */ -void __init assign_static_memory_11(struct domain *d, struct kernel_info *= kinfo, - const struct dt_device_node *node) -{ - u32 addr_cells, size_cells, reg_cells; - unsigned int nr_banks, bank =3D 0; - const __be32 *cell; - paddr_t pbase, psize; - mfn_t smfn; - int length; - - if ( parse_static_mem_prop(node, &addr_cells, &size_cells, &length, &c= ell) ) - { - printk(XENLOG_ERR - "%pd: failed to parse \"xen,static-mem\" property.\n", d); - goto fail; - } - reg_cells =3D addr_cells + size_cells; - nr_banks =3D length / (reg_cells * sizeof(u32)); - - if ( nr_banks > NR_MEM_BANKS ) - { - printk(XENLOG_ERR - "%pd: exceed max number of supported guest memory banks.\n"= , d); - goto fail; - } - - for ( ; bank < nr_banks; bank++ ) - { - smfn =3D acquire_static_memory_bank(d, &cell, addr_cells, size_cel= ls, - &pbase, &psize); - if ( mfn_eq(smfn, INVALID_MFN) ) - goto fail; - - printk(XENLOG_INFO "%pd: STATIC BANK[%u] %#"PRIpaddr"-%#"PRIpaddr"= \n", - d, bank, pbase, pbase + psize); - - /* One guest memory bank is matched with one physical memory bank.= */ - kinfo->mem.bank[bank].start =3D pbase; - if ( !append_static_memory_to_bank(d, &kinfo->mem.bank[bank], - smfn, psize) ) - goto fail; - - kinfo->unassigned_mem -=3D psize; - } - - kinfo->mem.nr_banks =3D nr_banks; - - /* - * The property 'memory' should match the amount of memory given to - * the guest. - * Currently, it is only possible to either acquire static memory or - * let Xen allocate. *Mixing* is not supported. - */ - if ( kinfo->unassigned_mem !=3D 0 ) - { - printk(XENLOG_ERR - "Size of \"memory\" property doesn't match up with the sum-= up of \"xen,static-mem\".\n"); - goto fail; - } - - return; - - fail: - panic("Failed to assign requested static memory for direct-map domain = %pd.\n", - d); -} - -#ifdef CONFIG_STATIC_SHM -static int __init acquire_nr_borrower_domain(struct domain *d, - paddr_t pbase, paddr_t psize, - unsigned long *nr_borrowers) -{ - unsigned int bank; - - /* Iterate reserved memory to find requested shm bank. */ - for ( bank =3D 0 ; bank < bootinfo.reserved_mem.nr_banks; bank++ ) - { - paddr_t bank_start =3D bootinfo.reserved_mem.bank[bank].start; - paddr_t bank_size =3D bootinfo.reserved_mem.bank[bank].size; - - if ( (pbase =3D=3D bank_start) && (psize =3D=3D bank_size) ) - break; - } - - if ( bank =3D=3D bootinfo.reserved_mem.nr_banks ) - return -ENOENT; - - *nr_borrowers =3D bootinfo.reserved_mem.bank[bank].nr_shm_borrowers; - - return 0; -} - -/* - * This function checks whether the static shared memory region is - * already allocated to dom_io. - */ -static bool __init is_shm_allocated_to_domio(paddr_t pbase) -{ - struct page_info *page; - struct domain *d; - - page =3D maddr_to_page(pbase); - d =3D page_get_owner_and_reference(page); - if ( d =3D=3D NULL ) - return false; - put_page(page); - - if ( d !=3D dom_io ) - { - printk(XENLOG_ERR - "shm memory node has already been allocated to a specific o= wner %pd, Please check your configuration\n", - d); - return false; - } - - return true; -} - -static mfn_t __init acquire_shared_memory_bank(struct domain *d, - paddr_t pbase, paddr_t psiz= e) -{ - mfn_t smfn; - unsigned long nr_pfns; - int res; - - /* - * Pages of statically shared memory shall be included - * into domain_tot_pages(). - */ - nr_pfns =3D PFN_DOWN(psize); - if ( (UINT_MAX - d->max_pages) < nr_pfns ) - { - printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages: %lu.\n", - d, nr_pfns); - return INVALID_MFN; - } - d->max_pages +=3D nr_pfns; - - smfn =3D maddr_to_mfn(pbase); - res =3D acquire_domstatic_pages(d, smfn, nr_pfns, 0); - if ( res ) - { - printk(XENLOG_ERR - "%pd: failed to acquire static memory: %d.\n", d, res); - d->max_pages -=3D nr_pfns; - return INVALID_MFN; - } - - return smfn; -} - -static int __init assign_shared_memory(struct domain *d, - uint32_t addr_cells, uint32_t size_= cells, - paddr_t pbase, paddr_t psize, - paddr_t gbase) -{ - mfn_t smfn; - int ret =3D 0; - unsigned long nr_pages, nr_borrowers, i; - struct page_info *page; - - printk("%pd: allocate static shared memory BANK %#"PRIpaddr"-%#"PRIpad= dr".\n", - d, pbase, pbase + psize); - - smfn =3D acquire_shared_memory_bank(d, pbase, psize); - if ( mfn_eq(smfn, INVALID_MFN) ) - return -EINVAL; - - /* - * DOMID_IO is not auto-translated (i.e. it sees RAM 1:1). So we do no= t need - * to create mapping in the P2M. - */ - nr_pages =3D PFN_DOWN(psize); - if ( d !=3D dom_io ) - { - ret =3D guest_physmap_add_pages(d, gaddr_to_gfn(gbase), smfn, - PFN_DOWN(psize)); - if ( ret ) - { - printk(XENLOG_ERR "Failed to map shared memory to %pd.\n", d); - return ret; - } - } - - /* - * Get the right amount of references per page, which is the number of - * borrower domains. - */ - ret =3D acquire_nr_borrower_domain(d, pbase, psize, &nr_borrowers); - if ( ret ) - return ret; - - /* - * Instead of letting borrower domain get a page ref, we add as many - * additional reference as the number of borrowers when the owner - * is allocated, since there is a chance that owner is created - * after borrower. - * So if the borrower is created first, it will cause adding pages - * in the P2M without reference. - */ - page =3D mfn_to_page(smfn); - for ( i =3D 0; i < nr_pages; i++ ) - { - if ( !get_page_nr(page + i, d, nr_borrowers) ) - { - printk(XENLOG_ERR - "Failed to add %lu references to page %"PRI_mfn".\n", - nr_borrowers, mfn_x(smfn) + i); - goto fail; - } - } - - return 0; - - fail: - while ( --i >=3D 0 ) - put_page_nr(page + i, nr_borrowers); - return ret; -} - -static int __init append_shm_bank_to_domain(struct kernel_info *kinfo, - paddr_t start, paddr_t size, - const char *shm_id) -{ - if ( kinfo->shm_mem.nr_banks >=3D NR_MEM_BANKS ) - return -ENOMEM; - - kinfo->shm_mem.bank[kinfo->shm_mem.nr_banks].start =3D start; - kinfo->shm_mem.bank[kinfo->shm_mem.nr_banks].size =3D size; - safe_strcpy(kinfo->shm_mem.bank[kinfo->shm_mem.nr_banks].shm_id, shm_i= d); - kinfo->shm_mem.nr_banks++; - - return 0; -} - -int __init process_shm(struct domain *d, struct kernel_info *kinfo, - const struct dt_device_node *node) -{ - struct dt_device_node *shm_node; - - dt_for_each_child_node(node, shm_node) - { - const struct dt_property *prop; - const __be32 *cells; - uint32_t addr_cells, size_cells; - paddr_t gbase, pbase, psize; - int ret =3D 0; - unsigned int i; - const char *role_str; - const char *shm_id; - bool owner_dom_io =3D true; - - if ( !dt_device_is_compatible(shm_node, "xen,domain-shared-memory-= v1") ) - continue; - - /* - * xen,shared-mem =3D ; - * TODO: pbase is optional. - */ - addr_cells =3D dt_n_addr_cells(shm_node); - size_cells =3D dt_n_size_cells(shm_node); - prop =3D dt_find_property(shm_node, "xen,shared-mem", NULL); - BUG_ON(!prop); - cells =3D (const __be32 *)prop->value; - device_tree_get_reg(&cells, addr_cells, addr_cells, &pbase, &gbase= ); - psize =3D dt_read_paddr(cells, size_cells); - if ( !IS_ALIGNED(pbase, PAGE_SIZE) || !IS_ALIGNED(gbase, PAGE_SIZE= ) ) - { - printk("%pd: physical address 0x%"PRIpaddr", or guest address = 0x%"PRIpaddr" is not suitably aligned.\n", - d, pbase, gbase); - return -EINVAL; - } - if ( !IS_ALIGNED(psize, PAGE_SIZE) ) - { - printk("%pd: size 0x%"PRIpaddr" is not suitably aligned\n", - d, psize); - return -EINVAL; - } - - for ( i =3D 0; i < PFN_DOWN(psize); i++ ) - if ( !mfn_valid(mfn_add(maddr_to_mfn(pbase), i)) ) - { - printk("%pd: invalid physical address 0x%"PRI_mfn"\n", - d, mfn_x(mfn_add(maddr_to_mfn(pbase), i))); - return -EINVAL; - } - - /* - * "role" property is optional and if it is defined explicitly, - * then the owner domain is not the default "dom_io" domain. - */ - if ( dt_property_read_string(shm_node, "role", &role_str) =3D=3D 0= ) - owner_dom_io =3D false; - - if ( dt_property_read_string(shm_node, "xen,shm-id", &shm_id) ) - { - printk("%pd: invalid \"xen,shm-id\" property", d); - return -EINVAL; - } - BUG_ON((strlen(shm_id) <=3D 0) || (strlen(shm_id) >=3D MAX_SHM_ID_= LENGTH)); - - /* - * DOMID_IO is a fake domain and is not described in the Device-Tr= ee. - * Therefore when the owner of the shared region is DOMID_IO, we w= ill - * only find the borrowers. - */ - if ( (owner_dom_io && !is_shm_allocated_to_domio(pbase)) || - (!owner_dom_io && strcmp(role_str, "owner") =3D=3D 0) ) - { - /* - * We found the first borrower of the region, the owner was not - * specified, so they should be assigned to dom_io. - */ - ret =3D assign_shared_memory(owner_dom_io ? dom_io : d, - addr_cells, size_cells, - pbase, psize, gbase); - if ( ret ) - return ret; - } - - if ( owner_dom_io || (strcmp(role_str, "borrower") =3D=3D 0) ) - { - /* Set up P2M foreign mapping for borrower domain. */ - ret =3D map_regions_p2mt(d, _gfn(PFN_UP(gbase)), PFN_DOWN(psiz= e), - _mfn(PFN_UP(pbase)), p2m_map_foreign_rw= ); - if ( ret ) - return ret; - } - - /* - * Record static shared memory region info for later setting - * up shm-node in guest device tree. - */ - ret =3D append_shm_bank_to_domain(kinfo, gbase, psize, shm_id); - if ( ret ) - return ret; - } - - return 0; -} -#endif /* CONFIG_STATIC_SHM */ -#endif - /* * When PCI passthrough is available we want to keep the * "linux,pci-domain" in sync for every host bridge. @@ -1274,85 +748,6 @@ int __init make_memory_node(const struct domain *d, return res; } =20 -#ifdef CONFIG_STATIC_SHM -static int __init make_shm_memory_node(const struct domain *d, - void *fdt, - int addrcells, int sizecells, - const struct meminfo *mem) -{ - unsigned int i =3D 0; - int res =3D 0; - - if ( mem->nr_banks =3D=3D 0 ) - return -ENOENT; - - /* - * For each shared memory region, a range is exposed under - * the /reserved-memory node as a child node. Each range sub-node is - * named xen-shmem@
. - */ - dt_dprintk("Create xen-shmem node\n"); - - for ( ; i < mem->nr_banks; i++ ) - { - uint64_t start =3D mem->bank[i].start; - uint64_t size =3D mem->bank[i].size; - const char compat[] =3D "xen,shared-memory-v1"; - /* Worst case addrcells + sizecells */ - __be32 reg[GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS]; - __be32 *cells; - unsigned int len =3D (addrcells + sizecells) * sizeof(__be32); - - res =3D domain_fdt_begin_node(fdt, "xen-shmem", mem->bank[i].start= ); - if ( res ) - return res; - - res =3D fdt_property(fdt, "compatible", compat, sizeof(compat)); - if ( res ) - return res; - - cells =3D reg; - dt_child_set_range(&cells, addrcells, sizecells, start, size); - - res =3D fdt_property(fdt, "reg", reg, len); - if ( res ) - return res; - - dt_dprintk("Shared memory bank %u: %#"PRIx64"->%#"PRIx64"\n", - i, start, start + size); - - res =3D fdt_property_string(fdt, "xen,id", mem->bank[i].shm_id); - if ( res ) - return res; - - /* - * TODO: - * - xen,offset: (borrower VMs only) - * 64 bit integer offset within the owner virtual machine's shar= ed - * memory region used for the mapping in the borrower VM - */ - res =3D fdt_property_u64(fdt, "xen,offset", 0); - if ( res ) - return res; - - res =3D fdt_end_node(fdt); - if ( res ) - return res; - } - - return res; -} -#else -static int __init make_shm_memory_node(const struct domain *d, - void *fdt, - int addrcells, int sizecells, - const struct meminfo *mem) -{ - ASSERT_UNREACHABLE(); - return -EOPNOTSUPP; -} -#endif - int __init make_resv_memory_node(const struct domain *d, void *fdt, int addrcells, int sizecells, @@ -2765,9 +2160,6 @@ static int __init construct_dom0(struct domain *d) { struct kernel_info kinfo =3D {}; int rc; -#ifdef CONFIG_STATIC_SHM - const struct dt_device_node *chosen =3D dt_find_node_by_path("/chosen"= ); -#endif =20 /* Sanity! */ BUG_ON(d->domain_id !=3D 0); @@ -2802,11 +2194,9 @@ static int __init construct_dom0(struct domain *d) allocate_memory_11(d, &kinfo); find_gnttab_region(d, &kinfo); =20 -#ifdef CONFIG_STATIC_SHM - rc =3D process_shm(d, &kinfo, chosen); + rc =3D process_shm_chosen(d, &kinfo); if ( rc < 0 ) return rc; -#endif =20 /* Map extra GIC MMIO, irqs and other hw stuffs to dom0. */ rc =3D gic_map_hwdom_extra_mappings(d); diff --git a/xen/arch/arm/include/asm/dom0less-build.h b/xen/arch/arm/inclu= de/asm/dom0less-build.h index 0d28fa1bee46..d95cb6234b62 100644 --- a/xen/arch/arm/include/asm/dom0less-build.h +++ b/xen/arch/arm/include/asm/dom0less-build.h @@ -8,8 +8,6 @@ #ifndef __ARM_DOM0LESS_BUILD_H_ #define __ARM_DOM0LESS_BUILD_H_ =20 -#include - void create_domUs(void); bool is_dom0less_mode(void); =20 diff --git a/xen/arch/arm/include/asm/domain_build.h b/xen/arch/arm/include= /asm/domain_build.h index d95cf376048f..b192bdadf3d8 100644 --- a/xen/arch/arm/include/asm/domain_build.h +++ b/xen/arch/arm/include/asm/domain_build.h @@ -40,9 +40,6 @@ int handle_device_interrupts(struct domain *d, struct dt_= device_node *dev, void set_interrupt(gic_interrupt_t interrupt, unsigned int irq, unsigned int cpumask, unsigned int level); =20 -int process_shm(struct domain *d, struct kernel_info *kinfo, - const struct dt_device_node *node); - #ifndef CONFIG_ACPI static inline int prepare_acpi(struct domain *d, struct kernel_info *kinfo) { @@ -54,27 +51,6 @@ static inline int prepare_acpi(struct domain *d, struct = kernel_info *kinfo) int prepare_acpi(struct domain *d, struct kernel_info *kinfo); #endif =20 -#ifdef CONFIG_STATIC_MEMORY -void allocate_static_memory(struct domain *d, struct kernel_info *kinfo, - const struct dt_device_node *node); -void assign_static_memory_11(struct domain *d, struct kernel_info *kinfo, - const struct dt_device_node *node); -#else -static inline void allocate_static_memory(struct domain *d, - struct kernel_info *kinfo, - const struct dt_device_node *nod= e) -{ - ASSERT_UNREACHABLE(); -} - -static inline void assign_static_memory_11(struct domain *d, - struct kernel_info *kinfo, - const struct dt_device_node *no= de) -{ - ASSERT_UNREACHABLE(); -} -#endif - #endif =20 /* diff --git a/xen/arch/arm/include/asm/static-memory.h b/xen/arch/arm/includ= e/asm/static-memory.h new file mode 100644 index 000000000000..0fe193b36861 --- /dev/null +++ b/xen/arch/arm/include/asm/static-memory.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * xen/arch/arm/include/asm/static-memory.h + * + * Copyright (C) 2023 Arm Ltd. + */ + +#ifndef __ARM_STATIC_MEMORY_H_ +#define __ARM_STATIC_MEMORY_H_ + +#include + +#ifdef CONFIG_STATIC_MEMORY + +void allocate_static_memory(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node); +void assign_static_memory_11(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node); +void init_staticmem_pages(void); + +#else /* !CONFIG_STATIC_MEMORY */ + +static inline void allocate_static_memory(struct domain *d, + struct kernel_info *kinfo, + const struct dt_device_node *nod= e) +{ + ASSERT_UNREACHABLE(); +} + +static inline void assign_static_memory_11(struct domain *d, + struct kernel_info *kinfo, + const struct dt_device_node *no= de) +{ + ASSERT_UNREACHABLE(); +} + +static inline void init_staticmem_pages(void) {}; + +#endif /* CONFIG_STATIC_MEMORY */ + +#endif /* __ARM_STATIC_MEMORY_H_ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End:b + */ diff --git a/xen/arch/arm/include/asm/static-shmem.h b/xen/arch/arm/include= /asm/static-shmem.h new file mode 100644 index 000000000000..5a8075fbee55 --- /dev/null +++ b/xen/arch/arm/include/asm/static-shmem.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * xen/arch/arm/include/asm/static-shmem.h + * + * Copyright (C) 2023 Arm Ltd. + */ + +#ifndef __ARM_STATIC_SHMEM_H_ +#define __ARM_STATIC_SHMEM_H_ + +#include + +#ifdef CONFIG_STATIC_SHM + +int make_shm_memory_node(const struct domain *d, void *fdt, int addrcells, + int sizecells, const struct meminfo *mem); + +int process_shm(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node); + +static inline int process_shm_chosen(struct domain *d, + struct kernel_info *kinfo) +{ + const struct dt_device_node *node =3D dt_find_node_by_path("/chosen"); + + return process_shm(d, kinfo, node); +} + +int process_shm_node(const void *fdt, int node, uint32_t address_cells, + uint32_t size_cells); + +#else /* !CONFIG_STATIC_SHM */ + +static inline int make_shm_memory_node(const struct domain *d, void *fdt, + int addrcells, int sizecells, + const struct meminfo *mem) +{ + ASSERT_UNREACHABLE(); + return -EOPNOTSUPP; +} + +static inline int process_shm(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node) +{ + return 0; +} + +static inline int process_shm_chosen(struct domain *d, + struct kernel_info *kinfo) +{ + return 0; +} + +static inline int process_shm_node(const void *fdt, int node, + uint32_t address_cells, uint32_t size_c= ells) +{ + printk("CONFIG_STATIC_SHM must be enabled for parsing static shared me= mory nodes\n"); + return -EINVAL; +} + +#endif /* CONFIG_STATIC_SHM */ + +#endif /* __ARM_STATIC_SHMEM_H_ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End:b + */ diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index db0299d540dc..f7de7170bacd 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include =20 @@ -758,30 +759,6 @@ static void __init init_pdx(void) } } =20 -/* Static memory initialization */ -static void __init init_staticmem_pages(void) -{ -#ifdef CONFIG_STATIC_MEMORY - unsigned int bank; - - for ( bank =3D 0 ; bank < bootinfo.reserved_mem.nr_banks; bank++ ) - { - if ( bootinfo.reserved_mem.bank[bank].type =3D=3D MEMBANK_STATIC_D= OMAIN ) - { - mfn_t bank_start =3D _mfn(PFN_UP(bootinfo.reserved_mem.bank[ba= nk].start)); - unsigned long bank_pages =3D PFN_DOWN(bootinfo.reserved_mem.ba= nk[bank].size); - mfn_t bank_end =3D mfn_add(bank_start, bank_pages); - - if ( mfn_x(bank_end) <=3D mfn_x(bank_start) ) - return; - - unprepare_staticmem_pages(mfn_to_page(bank_start), - bank_pages, false); - } - } -#endif -} - /* * Populate the boot allocator. * If a static heap was not provided by the admin, all the RAM but the diff --git a/xen/arch/arm/static-memory.c b/xen/arch/arm/static-memory.c new file mode 100644 index 000000000000..9aecdae28846 --- /dev/null +++ b/xen/arch/arm/static-memory.c @@ -0,0 +1,294 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * xen/arch/arm/static-memory.c + * + * Code related to the static memory functionality + * + * Copyright (C) 2023 Arm Ltd. + */ + +#include + +#include + +static bool __init append_static_memory_to_bank(struct domain *d, + struct membank *bank, + mfn_t smfn, + paddr_t size) +{ + int res; + unsigned int nr_pages =3D PFN_DOWN(size); + gfn_t sgfn; + + /* + * For direct-mapped domain, the GFN match the MFN. + * Otherwise, this is inferred on what has already been allocated + * in the bank. + */ + if ( !is_domain_direct_mapped(d) ) + sgfn =3D gaddr_to_gfn(bank->start + bank->size); + else + sgfn =3D gaddr_to_gfn(mfn_to_maddr(smfn)); + + res =3D guest_physmap_add_pages(d, sgfn, smfn, nr_pages); + if ( res ) + { + dprintk(XENLOG_ERR, "Failed to map pages to DOMU: %d", res); + return false; + } + + bank->size =3D bank->size + size; + + return true; +} + +static mfn_t __init acquire_static_memory_bank(struct domain *d, + const __be32 **cell, + u32 addr_cells, u32 size_ce= lls, + paddr_t *pbase, paddr_t *ps= ize) +{ + mfn_t smfn; + int res; + + device_tree_get_reg(cell, addr_cells, size_cells, pbase, psize); + ASSERT(IS_ALIGNED(*pbase, PAGE_SIZE) && IS_ALIGNED(*psize, PAGE_SIZE)); + if ( PFN_DOWN(*psize) > UINT_MAX ) + { + printk(XENLOG_ERR "%pd: static memory size too large: %#"PRIpaddr, + d, *psize); + return INVALID_MFN; + } + + smfn =3D maddr_to_mfn(*pbase); + res =3D acquire_domstatic_pages(d, smfn, PFN_DOWN(*psize), 0); + if ( res ) + { + printk(XENLOG_ERR + "%pd: failed to acquire static memory: %d.\n", d, res); + return INVALID_MFN; + } + + return smfn; +} + +static int __init parse_static_mem_prop(const struct dt_device_node *node, + u32 *addr_cells, u32 *size_cells, + int *length, const __be32 **cell) +{ + const struct dt_property *prop; + + prop =3D dt_find_property(node, "xen,static-mem", NULL); + + *addr_cells =3D dt_n_addr_cells(node); + *size_cells =3D dt_n_size_cells(node); + + *cell =3D (const __be32 *)prop->value; + *length =3D prop->length; + + return 0; +} + +/* Allocate memory from static memory as RAM for one specific domain d. */ +void __init allocate_static_memory(struct domain *d, struct kernel_info *k= info, + const struct dt_device_node *node) +{ + u32 addr_cells, size_cells, reg_cells; + unsigned int nr_banks, gbank, bank =3D 0; + const uint64_t rambase[] =3D GUEST_RAM_BANK_BASES; + const uint64_t ramsize[] =3D GUEST_RAM_BANK_SIZES; + const __be32 *cell; + u64 tot_size =3D 0; + paddr_t pbase, psize, gsize; + mfn_t smfn; + int length; + + if ( parse_static_mem_prop(node, &addr_cells, &size_cells, &length, &c= ell) ) + goto fail; + reg_cells =3D addr_cells + size_cells; + + /* + * The static memory will be mapped in the guest at the usual guest me= mory + * addresses (GUEST_RAM0_BASE, GUEST_RAM1_BASE) defined by + * xen/include/public/arch-arm.h. + */ + gbank =3D 0; + gsize =3D ramsize[gbank]; + kinfo->mem.bank[gbank].start =3D rambase[gbank]; + nr_banks =3D length / (reg_cells * sizeof (u32)); + + for ( ; bank < nr_banks; bank++ ) + { + smfn =3D acquire_static_memory_bank(d, &cell, addr_cells, size_cel= ls, + &pbase, &psize); + if ( mfn_eq(smfn, INVALID_MFN) ) + goto fail; + + printk(XENLOG_INFO "%pd: STATIC BANK[%u] %#"PRIpaddr"-%#"PRIpaddr"= \n", + d, bank, pbase, pbase + psize); + + while ( 1 ) + { + /* Map as much as possible the static range to the guest bank = */ + if ( !append_static_memory_to_bank(d, &kinfo->mem.bank[gbank],= smfn, + min(psize, gsize)) ) + goto fail; + + /* + * The current physical bank is fully mapped. + * Handle the next physical bank. + */ + if ( gsize >=3D psize ) + { + gsize =3D gsize - psize; + break; + } + /* + * When current guest bank is not enough to map, exhaust + * the current one and seek to the next. + * Before seeking to the next, check if we still have available + * guest bank. + */ + else if ( (gbank + 1) >=3D GUEST_RAM_BANKS ) + { + printk(XENLOG_ERR "Exhausted all possible guest banks.\n"); + goto fail; + } + else + { + psize =3D psize - gsize; + smfn =3D mfn_add(smfn, gsize >> PAGE_SHIFT); + /* Update to the next guest bank. */ + gbank++; + gsize =3D ramsize[gbank]; + kinfo->mem.bank[gbank].start =3D rambase[gbank]; + } + } + + tot_size +=3D psize; + } + + kinfo->mem.nr_banks =3D ++gbank; + + kinfo->unassigned_mem -=3D tot_size; + /* + * The property 'memory' should match the amount of memory given to the + * guest. + * Currently, it is only possible to either acquire static memory or l= et + * Xen allocate. *Mixing* is not supported. + */ + if ( kinfo->unassigned_mem ) + { + printk(XENLOG_ERR + "Size of \"memory\" property doesn't match up with the sum-= up of \"xen,static-mem\". Unsupported configuration.\n"); + goto fail; + } + + return; + + fail: + panic("Failed to allocate requested static memory for domain %pd.\n", = d); +} + +/* + * Allocate static memory as RAM for one specific domain d. + * The static memory will be directly mapped in the guest(Guest Physical + * Address =3D=3D Physical Address). + */ +void __init assign_static_memory_11(struct domain *d, struct kernel_info *= kinfo, + const struct dt_device_node *node) +{ + u32 addr_cells, size_cells, reg_cells; + unsigned int nr_banks, bank =3D 0; + const __be32 *cell; + paddr_t pbase, psize; + mfn_t smfn; + int length; + + if ( parse_static_mem_prop(node, &addr_cells, &size_cells, &length, &c= ell) ) + { + printk(XENLOG_ERR + "%pd: failed to parse \"xen,static-mem\" property.\n", d); + goto fail; + } + reg_cells =3D addr_cells + size_cells; + nr_banks =3D length / (reg_cells * sizeof(u32)); + + if ( nr_banks > NR_MEM_BANKS ) + { + printk(XENLOG_ERR + "%pd: exceed max number of supported guest memory banks.\n"= , d); + goto fail; + } + + for ( ; bank < nr_banks; bank++ ) + { + smfn =3D acquire_static_memory_bank(d, &cell, addr_cells, size_cel= ls, + &pbase, &psize); + if ( mfn_eq(smfn, INVALID_MFN) ) + goto fail; + + printk(XENLOG_INFO "%pd: STATIC BANK[%u] %#"PRIpaddr"-%#"PRIpaddr"= \n", + d, bank, pbase, pbase + psize); + + /* One guest memory bank is matched with one physical memory bank.= */ + kinfo->mem.bank[bank].start =3D pbase; + if ( !append_static_memory_to_bank(d, &kinfo->mem.bank[bank], + smfn, psize) ) + goto fail; + + kinfo->unassigned_mem -=3D psize; + } + + kinfo->mem.nr_banks =3D nr_banks; + + /* + * The property 'memory' should match the amount of memory given to + * the guest. + * Currently, it is only possible to either acquire static memory or + * let Xen allocate. *Mixing* is not supported. + */ + if ( kinfo->unassigned_mem !=3D 0 ) + { + printk(XENLOG_ERR + "Size of \"memory\" property doesn't match up with the sum-= up of \"xen,static-mem\".\n"); + goto fail; + } + + return; + + fail: + panic("Failed to assign requested static memory for direct-map domain = %pd.\n", + d); +} + +/* Static memory initialization */ +void __init init_staticmem_pages(void) +{ + unsigned int bank; + + for ( bank =3D 0 ; bank < bootinfo.reserved_mem.nr_banks; bank++ ) + { + if ( bootinfo.reserved_mem.bank[bank].type =3D=3D MEMBANK_STATIC_D= OMAIN ) + { + mfn_t bank_start =3D _mfn(PFN_UP(bootinfo.reserved_mem.bank[ba= nk].start)); + unsigned long bank_pages =3D PFN_DOWN(bootinfo.reserved_mem.ba= nk[bank].size); + mfn_t bank_end =3D mfn_add(bank_start, bank_pages); + + if ( mfn_x(bank_end) <=3D mfn_x(bank_start) ) + return; + + unprepare_staticmem_pages(mfn_to_page(bank_start), + bank_pages, false); + } + } +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c new file mode 100644 index 000000000000..fd826f486e8a --- /dev/null +++ b/xen/arch/arm/static-shmem.c @@ -0,0 +1,515 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * xen/arch/arm/static-shmem.c + * + * Code related to the static shared memory functionality + * + * Copyright (C) 2023 Arm Ltd. + */ + +#include +#include + +#include +#include + +static int __init acquire_nr_borrower_domain(struct domain *d, + paddr_t pbase, paddr_t psize, + unsigned long *nr_borrowers) +{ + unsigned int bank; + + /* Iterate reserved memory to find requested shm bank. */ + for ( bank =3D 0 ; bank < bootinfo.reserved_mem.nr_banks; bank++ ) + { + paddr_t bank_start =3D bootinfo.reserved_mem.bank[bank].start; + paddr_t bank_size =3D bootinfo.reserved_mem.bank[bank].size; + + if ( (pbase =3D=3D bank_start) && (psize =3D=3D bank_size) ) + break; + } + + if ( bank =3D=3D bootinfo.reserved_mem.nr_banks ) + return -ENOENT; + + *nr_borrowers =3D bootinfo.reserved_mem.bank[bank].nr_shm_borrowers; + + return 0; +} + +/* + * This function checks whether the static shared memory region is + * already allocated to dom_io. + */ +static bool __init is_shm_allocated_to_domio(paddr_t pbase) +{ + struct page_info *page; + struct domain *d; + + page =3D maddr_to_page(pbase); + d =3D page_get_owner_and_reference(page); + if ( d =3D=3D NULL ) + return false; + put_page(page); + + if ( d !=3D dom_io ) + { + printk(XENLOG_ERR + "shm memory node has already been allocated to a specific o= wner %pd, Please check your configuration\n", + d); + return false; + } + + return true; +} + +static mfn_t __init acquire_shared_memory_bank(struct domain *d, + paddr_t pbase, paddr_t psiz= e) +{ + mfn_t smfn; + unsigned long nr_pfns; + int res; + + /* + * Pages of statically shared memory shall be included + * into domain_tot_pages(). + */ + nr_pfns =3D PFN_DOWN(psize); + if ( (UINT_MAX - d->max_pages) < nr_pfns ) + { + printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages: %lu.\n", + d, nr_pfns); + return INVALID_MFN; + } + d->max_pages +=3D nr_pfns; + + smfn =3D maddr_to_mfn(pbase); + res =3D acquire_domstatic_pages(d, smfn, nr_pfns, 0); + if ( res ) + { + printk(XENLOG_ERR + "%pd: failed to acquire static memory: %d.\n", d, res); + d->max_pages -=3D nr_pfns; + return INVALID_MFN; + } + + return smfn; +} + +static int __init assign_shared_memory(struct domain *d, + uint32_t addr_cells, uint32_t size_= cells, + paddr_t pbase, paddr_t psize, + paddr_t gbase) +{ + mfn_t smfn; + int ret =3D 0; + unsigned long nr_pages, nr_borrowers, i; + struct page_info *page; + + printk("%pd: allocate static shared memory BANK %#"PRIpaddr"-%#"PRIpad= dr".\n", + d, pbase, pbase + psize); + + smfn =3D acquire_shared_memory_bank(d, pbase, psize); + if ( mfn_eq(smfn, INVALID_MFN) ) + return -EINVAL; + + /* + * DOMID_IO is not auto-translated (i.e. it sees RAM 1:1). So we do no= t need + * to create mapping in the P2M. + */ + nr_pages =3D PFN_DOWN(psize); + if ( d !=3D dom_io ) + { + ret =3D guest_physmap_add_pages(d, gaddr_to_gfn(gbase), smfn, + PFN_DOWN(psize)); + if ( ret ) + { + printk(XENLOG_ERR "Failed to map shared memory to %pd.\n", d); + return ret; + } + } + + /* + * Get the right amount of references per page, which is the number of + * borrower domains. + */ + ret =3D acquire_nr_borrower_domain(d, pbase, psize, &nr_borrowers); + if ( ret ) + return ret; + + /* + * Instead of letting borrower domain get a page ref, we add as many + * additional reference as the number of borrowers when the owner + * is allocated, since there is a chance that owner is created + * after borrower. + * So if the borrower is created first, it will cause adding pages + * in the P2M without reference. + */ + page =3D mfn_to_page(smfn); + for ( i =3D 0; i < nr_pages; i++ ) + { + if ( !get_page_nr(page + i, d, nr_borrowers) ) + { + printk(XENLOG_ERR + "Failed to add %lu references to page %"PRI_mfn".\n", + nr_borrowers, mfn_x(smfn) + i); + goto fail; + } + } + + return 0; + + fail: + while ( --i >=3D 0 ) + put_page_nr(page + i, nr_borrowers); + return ret; +} + +static int __init append_shm_bank_to_domain(struct kernel_info *kinfo, + paddr_t start, paddr_t size, + const char *shm_id) +{ + if ( kinfo->shm_mem.nr_banks >=3D NR_MEM_BANKS ) + return -ENOMEM; + + kinfo->shm_mem.bank[kinfo->shm_mem.nr_banks].start =3D start; + kinfo->shm_mem.bank[kinfo->shm_mem.nr_banks].size =3D size; + safe_strcpy(kinfo->shm_mem.bank[kinfo->shm_mem.nr_banks].shm_id, shm_i= d); + kinfo->shm_mem.nr_banks++; + + return 0; +} + +int __init process_shm(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node) +{ + struct dt_device_node *shm_node; + + dt_for_each_child_node(node, shm_node) + { + const struct dt_property *prop; + const __be32 *cells; + uint32_t addr_cells, size_cells; + paddr_t gbase, pbase, psize; + int ret =3D 0; + unsigned int i; + const char *role_str; + const char *shm_id; + bool owner_dom_io =3D true; + + if ( !dt_device_is_compatible(shm_node, "xen,domain-shared-memory-= v1") ) + continue; + + /* + * xen,shared-mem =3D ; + * TODO: pbase is optional. + */ + addr_cells =3D dt_n_addr_cells(shm_node); + size_cells =3D dt_n_size_cells(shm_node); + prop =3D dt_find_property(shm_node, "xen,shared-mem", NULL); + BUG_ON(!prop); + cells =3D (const __be32 *)prop->value; + device_tree_get_reg(&cells, addr_cells, addr_cells, &pbase, &gbase= ); + psize =3D dt_read_paddr(cells, size_cells); + if ( !IS_ALIGNED(pbase, PAGE_SIZE) || !IS_ALIGNED(gbase, PAGE_SIZE= ) ) + { + printk("%pd: physical address 0x%"PRIpaddr", or guest address = 0x%"PRIpaddr" is not suitably aligned.\n", + d, pbase, gbase); + return -EINVAL; + } + if ( !IS_ALIGNED(psize, PAGE_SIZE) ) + { + printk("%pd: size 0x%"PRIpaddr" is not suitably aligned\n", + d, psize); + return -EINVAL; + } + + for ( i =3D 0; i < PFN_DOWN(psize); i++ ) + if ( !mfn_valid(mfn_add(maddr_to_mfn(pbase), i)) ) + { + printk("%pd: invalid physical address 0x%"PRI_mfn"\n", + d, mfn_x(mfn_add(maddr_to_mfn(pbase), i))); + return -EINVAL; + } + + /* + * "role" property is optional and if it is defined explicitly, + * then the owner domain is not the default "dom_io" domain. + */ + if ( dt_property_read_string(shm_node, "role", &role_str) =3D=3D 0= ) + owner_dom_io =3D false; + + if ( dt_property_read_string(shm_node, "xen,shm-id", &shm_id) ) + { + printk("%pd: invalid \"xen,shm-id\" property", d); + return -EINVAL; + } + BUG_ON((strlen(shm_id) <=3D 0) || (strlen(shm_id) >=3D MAX_SHM_ID_= LENGTH)); + + /* + * DOMID_IO is a fake domain and is not described in the Device-Tr= ee. + * Therefore when the owner of the shared region is DOMID_IO, we w= ill + * only find the borrowers. + */ + if ( (owner_dom_io && !is_shm_allocated_to_domio(pbase)) || + (!owner_dom_io && strcmp(role_str, "owner") =3D=3D 0) ) + { + /* + * We found the first borrower of the region, the owner was not + * specified, so they should be assigned to dom_io. + */ + ret =3D assign_shared_memory(owner_dom_io ? dom_io : d, + addr_cells, size_cells, + pbase, psize, gbase); + if ( ret ) + return ret; + } + + if ( owner_dom_io || (strcmp(role_str, "borrower") =3D=3D 0) ) + { + /* Set up P2M foreign mapping for borrower domain. */ + ret =3D map_regions_p2mt(d, _gfn(PFN_UP(gbase)), PFN_DOWN(psiz= e), + _mfn(PFN_UP(pbase)), p2m_map_foreign_rw= ); + if ( ret ) + return ret; + } + + /* + * Record static shared memory region info for later setting + * up shm-node in guest device tree. + */ + ret =3D append_shm_bank_to_domain(kinfo, gbase, psize, shm_id); + if ( ret ) + return ret; + } + + return 0; +} + +int __init make_shm_memory_node(const struct domain *d, void *fdt, + int addrcells, int sizecells, + const struct meminfo *mem) +{ + unsigned int i =3D 0; + int res =3D 0; + + if ( mem->nr_banks =3D=3D 0 ) + return -ENOENT; + + /* + * For each shared memory region, a range is exposed under + * the /reserved-memory node as a child node. Each range sub-node is + * named xen-shmem@
. + */ + dt_dprintk("Create xen-shmem node\n"); + + for ( ; i < mem->nr_banks; i++ ) + { + uint64_t start =3D mem->bank[i].start; + uint64_t size =3D mem->bank[i].size; + const char compat[] =3D "xen,shared-memory-v1"; + /* Worst case addrcells + sizecells */ + __be32 reg[GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS]; + __be32 *cells; + unsigned int len =3D (addrcells + sizecells) * sizeof(__be32); + + res =3D domain_fdt_begin_node(fdt, "xen-shmem", mem->bank[i].start= ); + if ( res ) + return res; + + res =3D fdt_property(fdt, "compatible", compat, sizeof(compat)); + if ( res ) + return res; + + cells =3D reg; + dt_child_set_range(&cells, addrcells, sizecells, start, size); + + res =3D fdt_property(fdt, "reg", reg, len); + if ( res ) + return res; + + dt_dprintk("Shared memory bank %u: %#"PRIx64"->%#"PRIx64"\n", + i, start, start + size); + + res =3D fdt_property_string(fdt, "xen,id", mem->bank[i].shm_id); + if ( res ) + return res; + + /* + * TODO: + * - xen,offset: (borrower VMs only) + * 64 bit integer offset within the owner virtual machine's shar= ed + * memory region used for the mapping in the borrower VM + */ + res =3D fdt_property_u64(fdt, "xen,offset", 0); + if ( res ) + return res; + + res =3D fdt_end_node(fdt); + if ( res ) + return res; + } + + return res; +} + +int __init process_shm_node(const void *fdt, int node, uint32_t address_ce= lls, + uint32_t size_cells) +{ + const struct fdt_property *prop, *prop_id, *prop_role; + const __be32 *cell; + paddr_t paddr, gaddr, size; + struct meminfo *mem =3D &bootinfo.reserved_mem; + unsigned int i; + int len; + bool owner =3D false; + const char *shm_id; + + if ( address_cells < 1 || size_cells < 1 ) + { + printk("fdt: invalid #address-cells or #size-cells for static shar= ed memory node.\n"); + return -EINVAL; + } + + /* + * "xen,shm-id" property holds an arbitrary string with a strict limit + * on the number of characters, MAX_SHM_ID_LENGTH + */ + prop_id =3D fdt_get_property(fdt, node, "xen,shm-id", NULL); + if ( !prop_id ) + return -ENOENT; + shm_id =3D (const char *)prop_id->data; + if ( strnlen(shm_id, MAX_SHM_ID_LENGTH) =3D=3D MAX_SHM_ID_LENGTH ) + { + printk("fdt: invalid xen,shm-id %s, it must be limited to %u chara= cters\n", + shm_id, MAX_SHM_ID_LENGTH); + return -EINVAL; + } + + /* + * "role" property is optional and if it is defined explicitly, + * it must be either `owner` or `borrower`. + */ + prop_role =3D fdt_get_property(fdt, node, "role", NULL); + if ( prop_role ) + { + if ( !strcmp(prop_role->data, "owner") ) + owner =3D true; + else if ( strcmp(prop_role->data, "borrower") ) + { + printk("fdt: invalid `role` property for static shared memory = node.\n"); + return -EINVAL; + } + } + + /* + * xen,shared-mem =3D ; + * Memory region starting from physical address #paddr of #size shall + * be mapped to guest physical address #gaddr as static shared memory + * region. + */ + prop =3D fdt_get_property(fdt, node, "xen,shared-mem", &len); + if ( !prop ) + return -ENOENT; + + if ( len !=3D dt_cells_to_size(address_cells + size_cells + address_ce= lls) ) + { + if ( len =3D=3D dt_cells_to_size(size_cells + address_cells) ) + printk("fdt: host physical address must be chosen by users at = the moment.\n"); + + printk("fdt: invalid `xen,shared-mem` property.\n"); + return -EINVAL; + } + + cell =3D (const __be32 *)prop->data; + device_tree_get_reg(&cell, address_cells, address_cells, &paddr, &gadd= r); + size =3D dt_next_cell(size_cells, &cell); + + if ( !size ) + { + printk("fdt: the size for static shared memory region can not be z= ero\n"); + return -EINVAL; + } + + for ( i =3D 0; i < mem->nr_banks; i++ ) + { + /* + * Meet the following check: + * 1) The shm ID matches and the region exactly match + * 2) The shm ID doesn't match and the region doesn't overlap + * with an existing one + */ + if ( paddr =3D=3D mem->bank[i].start && size =3D=3D mem->bank[i].s= ize ) + { + if ( strncmp(shm_id, mem->bank[i].shm_id, MAX_SHM_ID_LENGTH) = =3D=3D 0 ) + break; + else + { + printk("fdt: xen,shm-id %s does not match for all the node= s using the same region.\n", + shm_id); + return -EINVAL; + } + } + else + { + paddr_t end =3D paddr + size; + paddr_t bank_end =3D mem->bank[i].start + mem->bank[i].size; + + if ( (end <=3D paddr) || (bank_end <=3D mem->bank[i].start) ) + { + printk("fdt: static shared memory region %s overflow\n", s= hm_id); + return -EINVAL; + } + + if ( check_reserved_regions_overlap(paddr, size) ) + return -EINVAL; + else + { + if ( strcmp(shm_id, mem->bank[i].shm_id) !=3D 0 ) + continue; + else + { + printk("fdt: different shared memory region could not = share the same shm ID %s\n", + shm_id); + return -EINVAL; + } + } + } + } + + if ( i =3D=3D mem->nr_banks ) + { + if ( i < NR_MEM_BANKS ) + { + /* Static shared memory shall be reserved from any other use. = */ + safe_strcpy(mem->bank[mem->nr_banks].shm_id, shm_id); + mem->bank[mem->nr_banks].start =3D paddr; + mem->bank[mem->nr_banks].size =3D size; + mem->bank[mem->nr_banks].type =3D MEMBANK_STATIC_DOMAIN; + mem->nr_banks++; + } + else + { + printk("Warning: Max number of supported memory regions reache= d.\n"); + return -ENOSPC; + } + } + /* + * keep a count of the number of borrowers, which later may be used + * to calculate the reference count. + */ + if ( !owner ) + mem->bank[i].nr_shm_borrowers++; + + return 0; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --=20 2.34.1 From nobody Thu May 16 00:42:45 2024 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; 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; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1695823341931790.9967014838519; Wed, 27 Sep 2023 07:02:21 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.608952.947822 (Exim 4.92) (envelope-from ) id 1qlV6u-0007jB-Rz; Wed, 27 Sep 2023 14:01:52 +0000 Received: by outflank-mailman (output) from mailman id 608952.947822; Wed, 27 Sep 2023 14:01:52 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1qlV6u-0007iJ-Jx; Wed, 27 Sep 2023 14:01:52 +0000 Received: by outflank-mailman (input) for mailman id 608952; Wed, 27 Sep 2023 14:01:51 +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 1qlV6t-0006eS-7l for xen-devel@lists.xenproject.org; Wed, 27 Sep 2023 14:01:51 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 66b63b3b-5d3e-11ee-878a-cb3800f73035; Wed, 27 Sep 2023 16:01:49 +0200 (CEST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 6292811FB; Wed, 27 Sep 2023 07:02:26 -0700 (PDT) Received: from e125770.cambridge.arm.com (e125770.arm.com [10.1.199.1]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 6D6DE3F59C; Wed, 27 Sep 2023 07:01:47 -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: 66b63b3b-5d3e-11ee-878a-cb3800f73035 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: wei.chen@arm.com, Stefano Stabellini , Julien Grall , Bertrand Marquis , Volodymyr Babchuk Subject: [PATCH v2 5/5] arm/dom0less: introduce Kconfig for dom0less feature Date: Wed, 27 Sep 2023 15:01:33 +0100 Message-Id: <20230927140133.631192-6-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230927140133.631192-1-luca.fancellu@arm.com> References: <20230927140133.631192-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1695823345411100001 Content-Type: text/plain; charset="utf-8" Introduce a Kconfig for the dom0less feature, enabled by default, to be able to choose if the feature should be compiled or not. Provide static inline stubs when the option is disabled for the functions externally visible. Use the new Kconfig to remove dom0less DT binding from the efi-boot.h code when the Kconfig is not enabled. Signed-off-by: Luca Fancellu --- xen/arch/arm/Kconfig | 9 +++++++++ xen/arch/arm/Makefile | 2 +- xen/arch/arm/efi/efi-boot.h | 4 ++++ xen/arch/arm/include/asm/dom0less-build.h | 12 ++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index 8dc704e802bc..f84b2cc22d08 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -89,6 +89,15 @@ config GICV2 Driver for the ARM Generic Interrupt Controller v2. If unsure, say Y =20 +config DOM0LESS_BOOT + bool "Dom0less boot support" if EXPERT + depends on ARM + default y + help + Dom0less boot support enables Xen to create and start domU guests during + Xen boot without the need of a control domain (Dom0), which could be + present anyway. + config GICV3 bool "GICv3 driver" depends on !NEW_VGIC diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 89ef0c9075b5..5daf8f10114d 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -15,7 +15,7 @@ obj-y +=3D cpufeature.o obj-y +=3D decode.o obj-y +=3D device.o obj-$(CONFIG_IOREQ_SERVER) +=3D dm.o -obj-y +=3D dom0less-build.init.o +obj-$(CONFIG_DOM0LESS_BOOT) +=3D dom0less-build.init.o obj-y +=3D domain.o obj-y +=3D domain_build.init.o obj-$(CONFIG_ARCH_MAP_DOMAIN_PAGE) +=3D domain_page.o diff --git a/xen/arch/arm/efi/efi-boot.h b/xen/arch/arm/efi/efi-boot.h index 1c3640bb65fd..689dc016d081 100644 --- a/xen/arch/arm/efi/efi-boot.h +++ b/xen/arch/arm/efi/efi-boot.h @@ -802,6 +802,7 @@ static int __init handle_module_node(const EFI_LOADED_I= MAGE *loaded_image, return 1; } =20 +#ifdef CONFIG_DOM0LESS_BOOT /* * This function checks for boot modules under the domU guest domain node * in the DT. @@ -849,6 +850,7 @@ static int __init handle_dom0less_domain_node(const EFI= _LOADED_IMAGE *loaded_ima =20 return mb_modules_found; } +#endif =20 /* * This function checks for xen domain nodes under the /chosen node for po= ssible @@ -876,6 +878,7 @@ static int __init efi_check_dt_boot(const EFI_LOADED_IM= AGE *loaded_image) { int ret; =20 +#ifdef CONFIG_DOM0LESS_BOOT if ( !fdt_node_check_compatible(fdt_efi, node, "xen,domain") ) { /* Found a node with compatible xen,domain; handle this node. = */ @@ -884,6 +887,7 @@ static int __init efi_check_dt_boot(const EFI_LOADED_IM= AGE *loaded_image) return ERROR_DT_MODULE_DOMU; } else +#endif { ret =3D handle_module_node(loaded_image, &dir_handle, node, ad= dr_len, size_len, false); diff --git a/xen/arch/arm/include/asm/dom0less-build.h b/xen/arch/arm/inclu= de/asm/dom0less-build.h index d95cb6234b62..859944eece16 100644 --- a/xen/arch/arm/include/asm/dom0less-build.h +++ b/xen/arch/arm/include/asm/dom0less-build.h @@ -8,9 +8,21 @@ #ifndef __ARM_DOM0LESS_BUILD_H_ #define __ARM_DOM0LESS_BUILD_H_ =20 +#ifdef CONFIG_DOM0LESS_BOOT + void create_domUs(void); bool is_dom0less_mode(void); =20 +#else /* !CONFIG_DOM0LESS_BOOT */ + +static inline void create_domUs(void) {} +static inline bool is_dom0less_mode(void) +{ + return false; +} + +#endif /* CONFIG_DOM0LESS_BOOT */ + #endif /* __ARM_DOM0LESS_BUILD_H_ */ =20 /* --=20 2.34.1