From nobody Sun May 12 06:03:57 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 1700819362850618.539383902982; Fri, 24 Nov 2023 01:49:22 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.640330.998323 (Exim 4.92) (envelope-from ) id 1r6Snu-00080E-A3; Fri, 24 Nov 2023 09:48:54 +0000 Received: by outflank-mailman (output) from mailman id 640330.998323; Fri, 24 Nov 2023 09:48:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1r6Snu-000807-6T; Fri, 24 Nov 2023 09:48:54 +0000 Received: by outflank-mailman (input) for mailman id 640330; Fri, 24 Nov 2023 09:48:53 +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 1r6Snt-0007mP-52 for xen-devel@lists.xenproject.org; Fri, 24 Nov 2023 09:48:53 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id ac405570-8aae-11ee-98e2-6d05b1d4d9a1; Fri, 24 Nov 2023 10:48:51 +0100 (CET) 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 6702913D5; Fri, 24 Nov 2023 01:49:37 -0800 (PST) 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 676DA3F7A6; Fri, 24 Nov 2023 01:48:50 -0800 (PST) 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: ac405570-8aae-11ee-98e2-6d05b1d4d9a1 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: Julien Grall , Michal Orzel Subject: [PATCH v6 1/5] arm/gicv2: make GICv2 driver and vGICv2 optional Date: Fri, 24 Nov 2023 09:48:37 +0000 Message-Id: <20231124094841.1475381-2-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231124094841.1475381-1-luca.fancellu@arm.com> References: <20231124094841.1475381-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1700819365251100003 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 --- Changes from v2: - No changes --- 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 7b5b0c0c05e7..57dc9957124f 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -80,6 +80,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 @@ -99,11 +107,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 c45b08b31eb0..d83dc25c0d8a 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -23,7 +23,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 @@ -58,7 +58,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 2dd2926b4144..814a41bcc502 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -2491,6 +2491,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; @@ -2542,6 +2543,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) @@ -2617,8 +2619,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 9b35a8c8a735..18289cd645ac 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 Sun May 12 06:03:57 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 1700819362374700.9183936460065; Fri, 24 Nov 2023 01:49:22 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.640332.998343 (Exim 4.92) (envelope-from ) id 1r6Snv-0008Tb-PZ; Fri, 24 Nov 2023 09:48:55 +0000 Received: by outflank-mailman (output) from mailman id 640332.998343; Fri, 24 Nov 2023 09:48:55 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1r6Snv-0008TU-Lr; Fri, 24 Nov 2023 09:48:55 +0000 Received: by outflank-mailman (input) for mailman id 640332; Fri, 24 Nov 2023 09:48:54 +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 1r6Snu-0007zs-2z for xen-devel@lists.xenproject.org; Fri, 24 Nov 2023 09:48:54 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id aca10602-8aae-11ee-9b0e-b553b5be7939; Fri, 24 Nov 2023 10:48:52 +0100 (CET) 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 10A3A1424; Fri, 24 Nov 2023 01:49:38 -0800 (PST) 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 2B0973F7A6; Fri, 24 Nov 2023 01:48:51 -0800 (PST) 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: aca10602-8aae-11ee-9b0e-b553b5be7939 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: Julien Grall Subject: [PATCH v6 2/5] xen/arm: Add asm/domain.h include to kernel.h Date: Fri, 24 Nov 2023 09:48:38 +0000 Message-Id: <20231124094841.1475381-3-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231124094841.1475381-1-luca.fancellu@arm.com> References: <20231124094841.1475381-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1700819363239100001 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 v2: - add Ack-by Julien 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 Sun May 12 06:03:57 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 1700819379502285.88050761471754; Fri, 24 Nov 2023 01:49:39 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.640333.998353 (Exim 4.92) (envelope-from ) id 1r6Sny-0000Je-39; Fri, 24 Nov 2023 09:48:58 +0000 Received: by outflank-mailman (output) from mailman id 640333.998353; Fri, 24 Nov 2023 09:48:58 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1r6Snx-0000JT-Uj; Fri, 24 Nov 2023 09:48:57 +0000 Received: by outflank-mailman (input) for mailman id 640333; Fri, 24 Nov 2023 09:48:56 +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 1r6Snv-0007zs-Uz for xen-devel@lists.xenproject.org; Fri, 24 Nov 2023 09:48:56 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id ad31199b-8aae-11ee-9b0e-b553b5be7939; Fri, 24 Nov 2023 10:48:53 +0100 (CET) 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 1111F143D; Fri, 24 Nov 2023 01:49:39 -0800 (PST) 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 CD0A83F7A6; Fri, 24 Nov 2023 01:48:51 -0800 (PST) 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: ad31199b-8aae-11ee-9b0e-b553b5be7939 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: Michal Orzel Subject: [PATCH v6 3/5] arm/dom0less: put dom0less feature code in a separate module Date: Fri, 24 Nov 2023 09:48:39 +0000 Message-Id: <20231124094841.1475381-4-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231124094841.1475381-1-luca.fancellu@arm.com> References: <20231124094841.1475381-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1700819381252100001 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 - allocate_bank_memory 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. The function allocate_bank_memory is used only by dom0less code at the moment, but it's been decided to leave it in domain_build.c in case that in the future the dom0 code can use it. Where spotted, fix code style issues. No functional change is intended. Signed-off-by: Luca Fancellu Reviewed-by: Michal Orzel --- Changes from v5: - remove unneeded include (Michal) - rebase on staging Changes from v4: - fixed name in inclusion macro __ASM_* instead of __ARM_*, fixed emacs local variable 'end:', style fix (Michal) Changes from v3: - remove header in dom0less-build.c (Michal) Changes from v2: - move allocate_bank_memory back in domain_build.c, remove header from dom0less-build.c. --- xen/arch/arm/Makefile | 1 + xen/arch/arm/dom0less-build.c | 1018 +++++++++++++++++ xen/arch/arm/domain_build.c | 1265 +++------------------ xen/arch/arm/include/asm/dom0less-build.h | 18 + xen/arch/arm/include/asm/domain_build.h | 60 + xen/arch/arm/include/asm/setup.h | 1 - xen/arch/arm/setup.c | 33 +- 7 files changed, 1238 insertions(+), 1158 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 d83dc25c0d8a..d65920b0a8cf 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -16,6 +16,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..1ca9d39043d6 --- /dev/null +++ b/xen/arch/arm/dom0less-build.c @@ -0,0 +1,1018 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#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 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 ) + { + rc =3D scan_pfdt_node(kinfo, pfdt, node_next, address_cells, size_= cells, + scan_passthrough_prop); + if ( rc ) + return rc; + + 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 814a41bcc502..90dba16e42c9 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include =20 @@ -118,7 +119,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 @@ -414,10 +415,8 @@ 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) +bool __init allocate_bank_memory(struct domain *d, struct kernel_info *kin= fo, + gfn_t sgfn, paddr_t tot_size) { int res; struct page_info *pg; @@ -478,49 +477,6 @@ static bool __init allocate_bank_memory(struct domain = *d, return true; } =20 -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, @@ -600,9 +556,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; @@ -706,9 +661,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; @@ -942,8 +896,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 @@ -1048,20 +1002,6 @@ static int __init process_shm(struct domain *d, stru= ct 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 /* @@ -1265,17 +1205,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); @@ -1320,8 +1253,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. @@ -1345,10 +1277,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; @@ -1484,10 +1416,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 */ @@ -1820,9 +1752,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" @@ -1939,7 +1871,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 @@ -1975,7 +1907,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"); @@ -2173,7 +2105,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 @@ -2491,773 +2423,161 @@ 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; + u64 val; =20 - /* 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)); + res =3D vgic_allocate_ppi(d); + if ( res < 0 ) + panic("Unable to allocate a PPI for the event channel interrupt\n"= ); =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); + d->arch.evtchn_irq =3D res; =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; - } + printk("Allocating PPI %u for event channel interrupt\n", + d->arch.evtchn_irq); =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; - } + /* Set the value of domain param HVM_PARAM_CALLBACK_IRQ */ + val =3D MASK_INSR(HVM_PARAM_CALLBACK_TYPE_PPI, + HVM_PARAM_CALLBACK_IRQ_TYPE_MASK); + /* Active-low level-sensitive */ + val |=3D MASK_INSR(HVM_PARAM_CALLBACK_TYPE_PPI_FLAG_LOW_LEVEL, + HVM_PARAM_CALLBACK_TYPE_PPI_FLAG_MASK); + val |=3D d->arch.evtchn_irq; + d->arch.hvm.params[HVM_PARAM_CALLBACK_IRQ] =3D val; +} =20 - 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; - } - } +static int __init get_evtchn_dt_property(const struct dt_device_node *np, + uint32_t *port, uint32_t *phandle) +{ + const __be32 *prop =3D NULL; + uint32_t len; =20 - /* - * 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; + prop =3D dt_get_property(np, "xen,evtchn", &len); + if ( !prop ) + { + printk(XENLOG_ERR "xen,evtchn property should not be empty.\n"); + return -EINVAL; + } =20 - /* - * 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 ) + if ( !len || len < dt_cells_to_size(STATIC_EVTCHN_NODE_SIZE_CELLS) ) { - 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 ) - { - rc =3D scan_pfdt_node(kinfo, pfdt, node_next, address_cells, size_= cells, - scan_passthrough_prop); - if ( rc ) - return rc; - - 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); - - /* Set the value of domain param HVM_PARAM_CALLBACK_IRQ */ - val =3D MASK_INSR(HVM_PARAM_CALLBACK_TYPE_PPI, - HVM_PARAM_CALLBACK_IRQ_TYPE_MASK); - /* Active-low level-sensitive */ - val |=3D MASK_INSR(HVM_PARAM_CALLBACK_TYPE_PPI_FLAG_LOW_LEVEL, - HVM_PARAM_CALLBACK_TYPE_PPI_FLAG_MASK); - val |=3D d->arch.evtchn_irq; - d->arch.hvm.params[HVM_PARAM_CALLBACK_IRQ] =3D val; -} - -static int __init get_evtchn_dt_property(const struct dt_device_node *np, - uint32_t *port, uint32_t *phandle) -{ - const __be32 *prop =3D NULL; - uint32_t len; - - prop =3D dt_get_property(np, "xen,evtchn", &len); - if ( !prop ) - { - printk(XENLOG_ERR "xen,evtchn property should not be empty.\n"); - return -EINVAL; - } - - if ( !len || len < dt_cells_to_size(STATIC_EVTCHN_NODE_SIZE_CELLS) ) - { - printk(XENLOG_ERR "xen,evtchn property value is not valid.\n"); + printk(XENLOG_ERR "xen,evtchn property value is not valid.\n"); return -EINVAL; } =20 @@ -3413,22 +2733,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]; @@ -3519,296 +2824,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..c5625925d940 --- /dev/null +++ b/xen/arch/arm/include/asm/dom0less-build.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ASM_DOM0LESS_BUILD_H_ +#define __ASM_DOM0LESS_BUILD_H_ + +void create_domUs(void); +bool is_dom0less_mode(void); + +#endif /* __ASM_DOM0LESS_BUILD_H_ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/include/asm/domain_build.h b/xen/arch/arm/include= /asm/domain_build.h index b9329c9ee032..b9ae0d170c5c 100644 --- a/xen/arch/arm/include/asm/domain_build.h +++ b/xen/arch/arm/include/asm/domain_build.h @@ -4,9 +4,47 @@ #include #include =20 +typedef __be32 gic_interrupt_t[3]; + +bool allocate_bank_memory(struct domain *d, struct kernel_info *kinfo, + gfn_t sgfn, paddr_t tot_size); +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 +55,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 ccb857ca2ea9..6d670d68aed3 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 9b9018574919..3f1081bed2e2 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -724,38 +725,6 @@ void __init populate_boot_allocator(void) } } =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 Sun May 12 06:03:57 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 17008193661417.983264096166749; Fri, 24 Nov 2023 01:49:26 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.640334.998359 (Exim 4.92) (envelope-from ) id 1r6Sny-0000NU-Fo; Fri, 24 Nov 2023 09:48:58 +0000 Received: by outflank-mailman (output) from mailman id 640334.998359; Fri, 24 Nov 2023 09:48:58 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1r6Sny-0000N3-8w; Fri, 24 Nov 2023 09:48:58 +0000 Received: by outflank-mailman (input) for mailman id 640334; Fri, 24 Nov 2023 09:48:56 +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 1r6Snw-0007mP-8G for xen-devel@lists.xenproject.org; Fri, 24 Nov 2023 09:48:56 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id ada343af-8aae-11ee-98e2-6d05b1d4d9a1; Fri, 24 Nov 2023 10:48:53 +0100 (CET) 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 B10FD1063 for ; Fri, 24 Nov 2023 01:49:39 -0800 (PST) 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 CB8C43F7A6 for ; Fri, 24 Nov 2023 01:48:52 -0800 (PST) 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: ada343af-8aae-11ee-98e2-6d05b1d4d9a1 From: Luca Fancellu To: xen-devel@lists.xenproject.org Subject: [PATCH v6 4/5] xen/arm: Move static memory build code in separate modules Date: Fri, 24 Nov 2023 09:48:40 +0000 Message-Id: <20231124094841.1475381-5-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231124094841.1475381-1-luca.fancellu@arm.com> References: <20231124094841.1475381-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1700819367265100005 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 Reviewed-by: Michal Orzel --- Changes from v5: - removed init_staticmem_pages prototype from setup.h, add static-memory.h include in arm{32,64}/mmu/mm.c, dropped Michal R-by given the changes Changes from v4: - Removed header from static-*.{c,h} files, fixed style issue, renamed inclusion define __ARM_* to __ASM_*, fixed emacs local variables. (Michal) Changes from v3: - Moved make_resv_memory_node from domain_build to static-shmem, make make_shm_memory_node static. Changes from v2: - no changes --- xen/arch/arm/Makefile | 2 + xen/arch/arm/arm32/mmu/mm.c | 1 + xen/arch/arm/arm64/mmu/mm.c | 1 + xen/arch/arm/bootfdt.c | 161 +----- xen/arch/arm/dom0less-build.c | 4 +- xen/arch/arm/domain_build.c | 654 +---------------------- xen/arch/arm/include/asm/domain_build.h | 26 - xen/arch/arm/include/asm/setup.h | 1 - xen/arch/arm/include/asm/static-memory.h | 45 ++ xen/arch/arm/include/asm/static-shmem.h | 66 +++ xen/arch/arm/setup.c | 24 - xen/arch/arm/static-memory.c | 287 ++++++++++ xen/arch/arm/static-shmem.c | 547 +++++++++++++++++++ 13 files changed, 954 insertions(+), 865 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 d65920b0a8cf..2fcc3c2535fd 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -51,6 +51,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/arm32/mmu/mm.c b/xen/arch/arm/arm32/mmu/mm.c index 94d6cab49cc9..cb441ca87c0d 100644 --- a/xen/arch/arm/arm32/mmu/mm.c +++ b/xen/arch/arm/arm32/mmu/mm.c @@ -6,6 +6,7 @@ #include #include #include +#include =20 static unsigned long opt_xenheap_megabytes __initdata; integer_param("xenheap_megabytes", opt_xenheap_megabytes); diff --git a/xen/arch/arm/arm64/mmu/mm.c b/xen/arch/arm/arm64/mmu/mm.c index e05d54c850ac..d2651c948698 100644 --- a/xen/arch/arm/arm64/mmu/mm.c +++ b/xen/arch/arm/arm64/mmu/mm.c @@ -5,6 +5,7 @@ #include =20 #include +#include =20 /* Override macros from asm/page.h to make them work with mfn_t */ #undef virt_to_mfn diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c index d73f8e497193..b1f03eb2fcdd 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_is_available(const void *fdt, int node) { @@ -423,166 +424,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 1ca9d39043d6..d39cbd969aca 100644 --- a/xen/arch/arm/dom0less-build.c +++ b/xen/arch/arm/dom0less-build.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include =20 bool __init is_dom0less_mode(void) { @@ -806,11 +808,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 90dba16e42c9..7eb766da9c63 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -31,6 +31,7 @@ #include #include #include +#include #include =20 #include @@ -477,533 +478,6 @@ bool __init allocate_bank_memory(struct domain *d, st= ruct kernel_info *kinfo, return true; } =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. @@ -1337,125 +811,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, - const struct meminfo *mem) -{ - int res =3D 0; - /* Placeholder for reserved-memory\0 */ - const char resvbuf[16] =3D "reserved-memory"; - - if ( mem->nr_banks =3D=3D 0 ) - /* No shared memory provided. */ - return 0; - - dt_dprintk("Create reserved-memory node\n"); - - res =3D fdt_begin_node(fdt, resvbuf); - if ( res ) - return res; - - res =3D fdt_property(fdt, "ranges", NULL, 0); - if ( res ) - return res; - - res =3D fdt_property_cell(fdt, "#address-cells", addrcells); - if ( res ) - return res; - - res =3D fdt_property_cell(fdt, "#size-cells", sizecells); - if ( res ) - return res; - - res =3D make_shm_memory_node(d, fdt, addrcells, sizecells, mem); - if ( res ) - return res; - - res =3D fdt_end_node(fdt); - - return res; -} - static int __init add_ext_regions(unsigned long s_gfn, unsigned long e_gfn, void *data) { @@ -2828,9 +2183,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); @@ -2865,11 +2217,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/domain_build.h b/xen/arch/arm/include= /asm/domain_build.h index b9ae0d170c5c..da9e6025f37c 100644 --- a/xen/arch/arm/include/asm/domain_build.h +++ b/xen/arch/arm/include/asm/domain_build.h @@ -10,8 +10,6 @@ bool allocate_bank_memory(struct domain *d, struct kernel= _info *kinfo, gfn_t sgfn, paddr_t tot_size); 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, @@ -42,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) { @@ -56,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/setup.h b/xen/arch/arm/include/asm/se= tup.h index 6d670d68aed3..bda3c07b8797 100644 --- a/xen/arch/arm/include/asm/setup.h +++ b/xen/arch/arm/include/asm/setup.h @@ -160,7 +160,6 @@ struct bootcmdline * boot_cmdline_find_by_name(const ch= ar *name); const char *boot_module_kind_as_string(bootmodule_kind kind); =20 void init_pdx(void); -void init_staticmem_pages(void); void populate_boot_allocator(void); void setup_mm(void); =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..3e3efd70c38d --- /dev/null +++ b/xen/arch/arm/include/asm/static-memory.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ASM_STATIC_MEMORY_H_ +#define __ASM_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 /* __ASM_STATIC_MEMORY_H_ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ 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..1536ff18b895 --- /dev/null +++ b/xen/arch/arm/include/asm/static-shmem.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ASM_STATIC_SHMEM_H_ +#define __ASM_STATIC_SHMEM_H_ + +#include + +#ifdef CONFIG_STATIC_SHM + +int make_resv_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_resv_memory_node(const struct domain *d, void *fdt, + int addrcells, int sizecells, + const struct meminfo *mem) +{ + return 0; +} + +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 /* __ASM_STATIC_SHMEM_H_ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 3f1081bed2e2..d2a47416e462 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -621,30 +621,6 @@ void __init init_pdx(void) } } =20 -/* Static memory initialization */ -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..cffbab7241b7 --- /dev/null +++ b/xen/arch/arm/static-memory.c @@ -0,0 +1,287 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#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..9097bc8b1511 --- /dev/null +++ b/xen/arch/arm/static-shmem.c @@ -0,0 +1,547 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#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; +} + +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; +} + +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; +} + +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 */ + const char resvbuf[16] =3D "reserved-memory"; + + if ( mem->nr_banks =3D=3D 0 ) + /* No shared memory provided. */ + return 0; + + dt_dprintk("Create reserved-memory node\n"); + + res =3D fdt_begin_node(fdt, resvbuf); + if ( res ) + return res; + + res =3D fdt_property(fdt, "ranges", NULL, 0); + if ( res ) + return res; + + res =3D fdt_property_cell(fdt, "#address-cells", addrcells); + if ( res ) + return res; + + res =3D fdt_property_cell(fdt, "#size-cells", sizecells); + if ( res ) + return res; + + res =3D make_shm_memory_node(d, fdt, addrcells, sizecells, mem); + if ( res ) + return res; + + res =3D fdt_end_node(fdt); + + return res; +} + +/* + * 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 Sun May 12 06:03:57 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 1700819370320430.9225521965403; Fri, 24 Nov 2023 01:49:30 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.640335.998366 (Exim 4.92) (envelope-from ) id 1r6Sny-0000V0-R4; Fri, 24 Nov 2023 09:48:58 +0000 Received: by outflank-mailman (output) from mailman id 640335.998366; Fri, 24 Nov 2023 09:48:58 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1r6Sny-0000TB-Iw; Fri, 24 Nov 2023 09:48:58 +0000 Received: by outflank-mailman (input) for mailman id 640335; Fri, 24 Nov 2023 09:48:56 +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 1r6Snw-0007zs-Jw for xen-devel@lists.xenproject.org; Fri, 24 Nov 2023 09:48:56 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id adfac723-8aae-11ee-9b0e-b553b5be7939; Fri, 24 Nov 2023 10:48:54 +0100 (CET) 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 5AB5813D5; Fri, 24 Nov 2023 01:49:40 -0800 (PST) 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 74F573F7A6; Fri, 24 Nov 2023 01:48:53 -0800 (PST) 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: adfac723-8aae-11ee-9b0e-b553b5be7939 From: Luca Fancellu To: xen-devel@lists.xenproject.org Cc: Michal Orzel Subject: [PATCH v6 5/5] arm/dom0less: introduce Kconfig for dom0less feature Date: Fri, 24 Nov 2023 09:48:41 +0000 Message-Id: <20231124094841.1475381-6-luca.fancellu@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231124094841.1475381-1-luca.fancellu@arm.com> References: <20231124094841.1475381-1-luca.fancellu@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1700819371111100002 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, do the same for allocate_bank_memory inside domain_build.c that currently is used only by dom0less-build.c module, but it's kept there provisioning its usage by dom0 code. Signed-off-by: Luca Fancellu Reviewed-by: Michal Orzel --- Changes from v5: - style fix, don't protect prototype (Michal), add R-by Michal since there are no rebase changes Changes from v4: - No changes Changes from v3: - Update Kconfig Changes from v2: - protect allocate_bank_memory with the new Kconfig --- xen/arch/arm/Kconfig | 8 ++++++++ xen/arch/arm/Makefile | 2 +- xen/arch/arm/domain_build.c | 2 ++ xen/arch/arm/efi/efi-boot.h | 4 ++++ xen/arch/arm/include/asm/dom0less-build.h | 12 ++++++++++++ xen/common/Kconfig | 2 +- 6 files changed, 28 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index 57dc9957124f..f73b62e50d00 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -88,6 +88,14 @@ config GICV2 Driver for the ARM Generic Interrupt Controller v2. If unsure, say Y =20 +config DOM0LESS_BOOT + bool "Dom0less boot support" if EXPERT + 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 2fcc3c2535fd..809772417c14 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -16,7 +16,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/domain_build.c b/xen/arch/arm/domain_build.c index 7eb766da9c63..df66fb88d8ec 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -416,6 +416,7 @@ static void __init allocate_memory_11(struct domain *d, } } =20 +#ifdef CONFIG_DOM0LESS_BOOT bool __init allocate_bank_memory(struct domain *d, struct kernel_info *kin= fo, gfn_t sgfn, paddr_t tot_size) { @@ -477,6 +478,7 @@ bool __init allocate_bank_memory(struct domain *d, stru= ct kernel_info *kinfo, =20 return true; } +#endif =20 /* * When PCI passthrough is available we want to keep the diff --git a/xen/arch/arm/efi/efi-boot.h b/xen/arch/arm/efi/efi-boot.h index 6e6db2445566..0cb29f90a066 100644 --- a/xen/arch/arm/efi/efi-boot.h +++ b/xen/arch/arm/efi/efi-boot.h @@ -787,6 +787,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. @@ -834,6 +835,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 @@ -861,6 +863,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. = */ @@ -869,6 +872,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 c5625925d940..00f92835eceb 100644 --- a/xen/arch/arm/include/asm/dom0less-build.h +++ b/xen/arch/arm/include/asm/dom0less-build.h @@ -3,9 +3,21 @@ #ifndef __ASM_DOM0LESS_BUILD_H_ #define __ASM_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 /* __ASM_DOM0LESS_BUILD_H_ */ =20 /* diff --git a/xen/common/Kconfig b/xen/common/Kconfig index 4d6fe051641d..310ad4229cdf 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -100,7 +100,7 @@ config NUMA =20 config STATIC_MEMORY bool "Static Allocation Support (UNSUPPORTED)" if UNSUPPORTED - depends on ARM + depends on DOM0LESS_BOOT help Static Allocation refers to system or sub-system(domains) for which memory areas are pre-defined by configuration using physical --=20 2.34.1