From nobody Sat Nov 1 21:07:55 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; 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=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1746203489; cv=none; d=zohomail.com; s=zohoarc; b=LyfzdPtrL15chv3QlQHJIvBInO+iXP8z3eA/7C2zqoZLiht6bGquC6BQV4x5P7wzvB5KoIbtEMsEuFWyElfi/rbLc097cen6tJlWZ4z2xO5W6Ip124bg+hAoLjaQhFDYHOjWjX0ZXQI87cTMxzcgT1eypx2nNcVj/b7vjXJExfk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746203489; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=+jFw3h4Q9XYaNyP0ZWtKpY/WJbt8g8MpajB8UOqpIWc=; b=lfY2VGAwJT7EXRo3kz7R1BUekyYa6jIcH/B/5sygh/22T0PN/z9Ru6pnEb0umtu6HM7mOeiyjXk0pqGuJ2vjGTYQlwhpp4Nr1c4GfVj72Y3Xs9Z9/ijx296yiTUzLucRJ5GfgjcCdrvsqSGgluzuk8WSbqYXCXkm3iIGawgzEp4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1746203489748587.2197425319591; Fri, 2 May 2025 09:31:29 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.974868.1362625 (Exim 4.92) (envelope-from ) id 1uAtI9-00031w-Jl; Fri, 02 May 2025 16:31:13 +0000 Received: by outflank-mailman (output) from mailman id 974868.1362625; Fri, 02 May 2025 16:31:13 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uAtI9-00031p-Gg; Fri, 02 May 2025 16:31:13 +0000 Received: by outflank-mailman (input) for mailman id 974868; Fri, 02 May 2025 16:31:12 +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 1uAtAC-0005rZ-S4 for xen-devel@lists.xenproject.org; Fri, 02 May 2025 16:23:01 +0000 Received: from mail-ej1-x634.google.com (mail-ej1-x634.google.com [2a00:1450:4864:20::634]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id b447a7c1-2771-11f0-9eb4-5ba50f476ded; Fri, 02 May 2025 18:22:55 +0200 (CEST) Received: by mail-ej1-x634.google.com with SMTP id a640c23a62f3a-ac2a81e41e3so394156766b.1 for ; Fri, 02 May 2025 09:22:55 -0700 (PDT) Received: from fedora.. (user-109-243-69-225.play-internet.pl. [109.243.69.225]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ad1894c01f2sm68158766b.119.2025.05.02.09.22.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 May 2025 09:22:54 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: b447a7c1-2771-11f0-9eb4-5ba50f476ded DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746202975; x=1746807775; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+jFw3h4Q9XYaNyP0ZWtKpY/WJbt8g8MpajB8UOqpIWc=; b=aQmdyfD+mrQOFFCF0Pwy57zgYla5ex1Q38J4dJKEUq9bGNZS1crBikATkFFG7tMY0v 6C8LcoUO7YNeDPRKaTOnYFq+qpt6oNBPrb0PTw0fmi+EP5/3wNzJHj16BbiJ2UDEntA3 BPKbLPEcdnliqJbEk7ZqZUt/IwuAkE0Y+jvNoLPfW7j5eGAuJ42eplAicz/gDuQgpLOb FL9x+99tF3wpKhEXe/YPVrPSj8PRHRhziQjl3goauyaqDHulzKQjfbuOhnQvNT7tOItr LU/PkB3K7TjTl3PEKT4RuGGxXfifH6Mlt+MyDkXdB4a+C3vrkcz5JViWEM+J250iMIWD XN4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746202975; x=1746807775; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=+jFw3h4Q9XYaNyP0ZWtKpY/WJbt8g8MpajB8UOqpIWc=; b=uM1uEyWt1PRg4gdIDce2cgtVQL0vuPCHD6Qr04Phtfuz724/RoDqEMAQPTjM+3IQ6r xbrI1vwY2jgR/uwQHLu9Sp1NogQVouu6RzbN90Zj5DNVfmoOkieCJKH8+AnGAnOxtYBX MA59TLKbV2S5dB1s6X6bIyUcUhZ/fr8CH2UuyiUQxgWIaK6Ox1cO5VZPgaoXxe3Hk3j7 okwKdXMk1uQNmyoi0iBUKOE62wcCAWZA4L4/wjAJCIwDvQpgYF2nwMovMXoN1mFMON1B k3Lsp7ptfMvu4u59sxbJVqL4oS7R3gdMD//gxcT0PCKQsQeh5n0Hh8g5J86louJ/4GkV 4GkA== X-Gm-Message-State: AOJu0YziSWofqvAoTxgo468uTnhL/CUqD8ib7PqpXEKUTr2+4EDvg/U8 z/d7FNY/a6Wgq749LsDjkAIQdnep+tVdlpvLbnhMF7p+ceZFk4rTzHUuFw== X-Gm-Gg: ASbGncsyJwhmdit6FJaqTzZOm23Th4cFSJYekkp/uyYX5jvzdGhUwA9Be9/LUJW0nvj DpQknMt/agcoHwVU4ckAaz1C8aslSEXRY4O+4Wxu55rbmW4UQcy+iyBZEEcz9GLdwmPY6RJ6wgq SfN4SoKrXq0miaTdi07MHBRpaX6JTbFSPI7O5QHFYSJ0VfHvp+KGlOXvHPKgb2HbYn3/PMeD3S/ e1TkMeoBgsVqWweIGg+XhqQtzhMhmFiBS9aca0Dk2m0eWXkTI2QWLbnNvM9y/qMNsEcUtWZuZNM BmlmapsaRPf7mxItX/UcDC1BWMMa38FlhB7HoEkuagv2qNjg52VYbICW8nRMyJf9P2I5vUxryk+ L/uOHaGYfcFmdDgpCWGOb X-Google-Smtp-Source: AGHT+IGrsgFMj3uuhYBpdoLcgRI+pbhUn22HD0W7o+9g2/s2oqcTWR5L5u0N/xcBOWeFbbfR//gqyQ== X-Received: by 2002:a17:907:1688:b0:ac4:493:403 with SMTP id a640c23a62f3a-ad17aef2851mr305912266b.37.1746202974817; Fri, 02 May 2025 09:22:54 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Oleksii Kurochko , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk , Andrew Cooper , Anthony PERARD , Jan Beulich , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Subject: [PATCH v3 8/8] xen/common: dom0less: introduce common dom0less-build.c Date: Fri, 2 May 2025 18:22:38 +0200 Message-ID: <76390ef52f108b580e1c397ed178ceadf1ae53c4.1746199009.git.oleksii.kurochko@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1746203491192019000 Content-Type: text/plain; charset="utf-8" Part of Arm's dom0less-build.c could be common between architectures which = are using device tree files to create guest domains. Thereby move some parts of Arm's dom0less-build.c to common code with minor changes. As a part of theses changes the following changes are introduced: - Introduce make_arch_nodes() to cover arch-specific nodes. For example, in case of Arm, it is PSCI and vpl011 nodes. - Introduce set_domain_type() to abstract a way how setting of domain type happens. For example, RISC-V won't have this member of arch_domain struct= ure as vCPUs will always have the same bitness as hypervisor. In case of Arm,= it is possible that Arm64 could create 32-bit and 64-bit domains. - Introduce init_vuart() to cover details of virtual uart initialization. - Introduce init_intc_phandle() to cover some details of interrupt controll= er phandle initialization. As an example, RISC-V could have different name f= or interrupt controller node ( APLIC, PLIC, IMSIC, etc ) but the code in domain_handle_dtb_bootmodule() could handle only one interrupt controller node name. - s/make_gic_domU_node/make_intc_domU_node as GIC is Arm specific naming and add prototype of make_intc_domU_node() to dom0less-build.h The following functions are moved to xen/common/device-tree: - Functions which are moved as is: - domain_p2m_pages(). - handle_passthrough_prop(). - handle_prop_pfdt(). - scan_pfdt_node(). - check_partial_fdt(). - Functions which are moved with some minor changes: - alloc_xenstore_evtchn(): - ifdef-ing by CONFIG_HVM accesses to hvm.params. - prepare_dtb_domU(): - ifdef-ing access to gnttab_{start,size} by CONFIG_GRANT_TABLE. - s/make_gic_domU_node/make_intc_domU_node. - Add call of make_arch_nodes(). - domain_handle_dtb_bootmodule(): - hide details of interrupt controller phandle initialization by calling init_intc_phandle(). - Update the comment above init_intc_phandle(): s/gic/interrupt controlle= r. - construct_domU(): - ifdef-ing by CONFIG_HVM accesses to hvm.params. - Call init_vuart() to hide Arm's vpl011_init() details there. - Add call of set_domain_type() instead of setting kinfo->arch.type expli= citly. Some parts of dom0less-build.c are wraped by #ifdef CONFIG_STATIC_{SHMEM,ME= MORY} as not all archs support these configs. Signed-off-by: Oleksii Kurochko --- Change in v3: - Align construct_domU() with the current staging. - Align alloc_xenstore_params() with the current staging. - Move defintion of XENSTORE_PFN_LATE_ALLOC to common and declaration of need_xenstore to common. --- Change in v2: - Wrap by #ifdef CONFIG_STATIC_* inclusions of and . Wrap also the code which uses something from the mentioned headers. - Add handling of legacy case in construct_domU(). - Use xen/fdt-kernel.h and xen/fdt-domain-build.h instead of asm/*. - Update the commit message. --- xen/arch/arm/dom0less-build.c | 714 ++--------------------- xen/common/device-tree/dom0less-build.c | 699 ++++++++++++++++++++++ xen/include/asm-generic/dom0less-build.h | 18 +- 3 files changed, 751 insertions(+), 680 deletions(-) diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c index 0310579863..627c212b3b 100644 --- a/xen/arch/arm/dom0less-build.c +++ b/xen/arch/arm/dom0less-build.c @@ -25,8 +25,6 @@ #include #include =20 -bool __initdata need_xenstore; - #ifdef CONFIG_VGICV2 static int __init make_gicv2_domU_node(struct kernel_info *kinfo) { @@ -152,7 +150,7 @@ static int __init make_gicv3_domU_node(struct kernel_in= fo *kinfo) } #endif =20 -static int __init make_gic_domU_node(struct kernel_info *kinfo) +int __init make_intc_domU_node(struct kernel_info *kinfo) { switch ( kinfo->d->arch.vgic.version ) { @@ -218,708 +216,60 @@ static int __init make_vpl011_uart_node(struct kerne= l_info *kinfo) } #endif =20 -/* - * 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", - 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 __init make_arch_nodes(struct kernel_info *kinfo) { - 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 ) - { - uint32_t phandle_intc =3D fdt_get_phandle(pfdt, node_next); - - if ( phandle_intc !=3D 0 ) - kinfo->phandle_intc =3D phandle_intc; - 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_intc =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; + int ret; =20 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(kinfo, addrcells, sizecells, - kernel_info_get_mem(kinfo)); - if ( ret ) - goto err; - - ret =3D make_resv_memory_node(kinfo, addrcells, sizecells); - 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_intc. - */ - 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; + return -EINVAL; =20 if ( kinfo->vuart ) { - 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; + return -EINVAL; } =20 - 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; } =20 -#define XENSTORE_PFN_OFFSET 1 -static int __init alloc_xenstore_page(struct domain *d) +/* TODO: make arch.type generic ? */ +#ifdef CONFIG_ARM_64 +void __init set_domain_type(struct domain *d, struct kernel_info *kinfo) { - struct page_info *xenstore_pg; - struct xenstore_domain_interface *interface; - mfn_t mfn; - gfn_t gfn; - int rc; - - if ( (UINT_MAX - d->max_pages) < 1 ) - { - printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages by 1 page= .\n", - d); - return -EINVAL; - } - - d->max_pages +=3D 1; - xenstore_pg =3D alloc_domheap_page(d, MEMF_bits(32)); - if ( xenstore_pg =3D=3D NULL && is_64bit_domain(d) ) - xenstore_pg =3D alloc_domheap_page(d, 0); - if ( xenstore_pg =3D=3D NULL ) - return -ENOMEM; - - mfn =3D page_to_mfn(xenstore_pg); - if ( !mfn_x(mfn) ) - return -ENOMEM; - - if ( !is_domain_direct_mapped(d) ) - gfn =3D gaddr_to_gfn(GUEST_MAGIC_BASE + - (XENSTORE_PFN_OFFSET << PAGE_SHIFT)); - else - gfn =3D gaddr_to_gfn(mfn_to_maddr(mfn)); - - rc =3D guest_physmap_add_page(d, gfn, mfn, 0); - if ( rc ) - { - free_domheap_page(xenstore_pg); - return rc; - } - - d->arch.hvm.params[HVM_PARAM_STORE_PFN] =3D gfn_x(gfn); - interface =3D map_domain_page(mfn); - interface->connection =3D XENSTORE_RECONNECT; - unmap_domain_page(interface); - - return 0; + /* type must be set before allocate memory */ + d->arch.type =3D kinfo->arch.type; } - -static int __init alloc_xenstore_params(struct kernel_info *kinfo) +#else +void __init set_domain_type(struct domain *d, struct kernel_info *kinfo) { - struct domain *d =3D kinfo->d; - int rc =3D 0; - - if ( (kinfo->dom0less_feature & (DOM0LESS_XENSTORE | DOM0LESS_XS_LEGAC= Y)) - =3D=3D (DOM0LESS_XENSTORE | DOM0LESS_XS_L= EGACY) ) - d->arch.hvm.params[HVM_PARAM_STORE_PFN] =3D XENSTORE_PFN_LATE_ALLO= C; - else if ( kinfo->dom0less_feature & DOM0LESS_XENSTORE ) - { - rc =3D alloc_xenstore_page(d); - if ( rc < 0 ) - return rc; - } - - return rc; + /* Nothing to do */ } +#endif =20 -static void __init domain_vcpu_affinity(struct domain *d, - const struct dt_device_node *node) +int __init init_vuart(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node) { - struct dt_device_node *np; - - dt_for_each_child_node(node, np) - { - const char *hard_affinity_str =3D NULL; - uint32_t val; - int rc; - struct vcpu *v; - cpumask_t affinity; - - if ( !dt_device_is_compatible(np, "xen,vcpu") ) - continue; - - if ( !dt_property_read_u32(np, "id", &val) ) - panic("Invalid xen,vcpu node for domain %s\n", dt_node_name(no= de)); - - if ( val >=3D d->max_vcpus ) - panic("Invalid vcpu_id %u for domain %s, max_vcpus=3D%u\n", va= l, - dt_node_name(node), d->max_vcpus); - - v =3D d->vcpu[val]; - rc =3D dt_property_read_string(np, "hard-affinity", &hard_affinity= _str); - if ( rc < 0 ) - continue; - - cpumask_clear(&affinity); - while ( *hard_affinity_str !=3D '\0' ) - { - unsigned int start, end; - - start =3D simple_strtoul(hard_affinity_str, &hard_affinity_str= , 0); - - if ( *hard_affinity_str =3D=3D '-' ) /* Range */ - { - hard_affinity_str++; - end =3D simple_strtoul(hard_affinity_str, &hard_affinity_s= tr, 0); - } - else /* Single value */ - end =3D start; - - if ( end >=3D nr_cpu_ids ) - panic("Invalid pCPU %u for domain %s\n", end, dt_node_name= (node)); - - for ( ; start <=3D end; start++ ) - cpumask_set_cpu(start, &affinity); - - if ( *hard_affinity_str =3D=3D ',' ) - hard_affinity_str++; - else if ( *hard_affinity_str !=3D '\0' ) - break; - } + int rc =3D 0; =20 - rc =3D vcpu_set_hard_affinity(v, &affinity); - if ( rc ) - panic("vcpu%d: failed (rc=3D%d) to set hard affinity for domai= n %s\n", - v->vcpu_id, rc, dt_node_name(node)); - } -} + kinfo->vuart =3D dt_property_read_bool(node, "vpl011"); =20 -#ifdef CONFIG_ARCH_PAGING_MEMPOOL -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. + * 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. */ - 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 domain_p2m_set_allocation(struct domain *d, uint64_t mem, - const struct dt_device_node *n= ode) -{ - unsigned long p2m_pages; - uint32_t p2m_mem_mb; - int rc; - - 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); - - return rc; -} -#else /* !CONFIG_ARCH_PAGING_MEMPOOL */ -static inline int domain_p2m_set_allocation(struct domain *d, uint64_t mem, - const struct dt_device_node *n= ode) -{ - return 0; -} -#endif /* CONFIG_ARCH_PAGING_MEMPOOL */ - -int __init construct_domU(struct domain *d, - const struct dt_device_node *node) -{ - struct kernel_info kinfo =3D KERNEL_INFO_INIT; - const char *dom0less_enhanced; - int rc; - u64 mem; - - 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 domain_p2m_set_allocation(d, mem, node); - if ( rc !=3D 0 ) - return rc; - - printk("*** LOADING DOMU cpus=3D%u memory=3D%#"PRIx64"KB ***\n", - d->max_vcpus, mem); - - kinfo.vuart =3D dt_property_read_bool(node, "vpl011"); - if ( kinfo.vuart && is_hardware_domain(d) ) - panic("hardware domain cannot specify vpl011\n"); - - 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")) ) - { - need_xenstore =3D true; - kinfo.dom0less_feature =3D DOM0LESS_ENHANCED; - } - else if ( rc =3D=3D 0 && !strcmp(dom0less_enhanced, "legacy") ) - { - need_xenstore =3D true; - kinfo.dom0less_feature =3D DOM0LESS_ENHANCED_LEGACY; - } - 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.arch.type; -#endif - if ( is_hardware_domain(d) ) - { - rc =3D construct_hwdom(&kinfo, node); - if ( rc < 0 ) - return rc; - } - else + if ( kinfo->vuart ) { - 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); - - rc =3D process_shm(d, &kinfo, node); - if ( rc < 0 ) - return rc; - - /* - * Base address and irq number are needed when creating vpl011 dev= ice - * tree node in prepare_dtb_domU, so initialization on related var= iables - * shall be done first. - */ - if ( kinfo.vuart ) - { - 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); + rc =3D domain_vpl011_init(d, NULL); if ( rc < 0 ) return rc; } =20 - domain_vcpu_affinity(d, node); - - return alloc_xenstore_params(&kinfo); + return rc; } =20 void __init arch_create_domUs(struct dt_device_node *node, @@ -995,6 +345,22 @@ void __init arch_create_domUs(struct dt_device_node *n= ode, } } =20 +int __init init_intc_phandle(struct kernel_info *kinfo, const char *name, + const int node_next, const void *pfdt) +{ + if ( dt_node_cmp(name, "gic") =3D=3D 0 ) + { + uint32_t phandle_intc =3D fdt_get_phandle(pfdt, node_next); + + if ( phandle_intc !=3D 0 ) + kinfo->phandle_intc =3D phandle_intc; + + return 0; + } + + return 1; +} + /* * Local variables: * mode: C diff --git a/xen/common/device-tree/dom0less-build.c b/xen/common/device-tr= ee/dom0less-build.c index a01a8b6b1a..c3face5b90 100644 --- a/xen/common/device-tree/dom0less-build.c +++ b/xen/common/device-tree/dom0less-build.c @@ -3,24 +3,43 @@ #include #include #include +#include #include #include +#include +#include #include #include +#include #include +#include #include +#include #include #include #include +#include =20 #include #include #include +#include =20 #include #include =20 +#ifdef CONFIG_STATIC_MEMORY +#include +#endif + +#ifdef CONFIG_STATIC_SHM +#include +#endif + +#define XENSTORE_PFN_LATE_ALLOC UINT64_MAX + static domid_t __initdata xs_domid =3D DOMID_INVALID; +static bool __initdata need_xenstore; =20 void __init set_xs_domain(struct domain *d) { @@ -109,6 +128,686 @@ static void __init initialize_domU_xenstore(void) } } =20 +/* + * 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", + 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 /$(interrupt_controller) /aliases /passthrough, + * ignore the rest. + * They don't have to be parsed in order. + * + * Take the interrupt controller phandle value from the special + * interrupt controller node in the DTB fragment. + */ + if ( init_intc_phandle(kinfo, name, node_next, pfdt) =3D=3D 0 ) + 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_intc =3D GUEST_PHANDLE_GIC; + +#ifdef CONFIG_GRANT_TABLE + kinfo->gnttab_start =3D GUEST_GNTTAB_BASE; + kinfo->gnttab_size =3D GUEST_GNTTAB_SIZE; +#endif + + 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_cpus_node(d, kinfo->fdt); + if ( ret ) + goto err; + + ret =3D make_memory_node(kinfo, addrcells, sizecells, + kernel_info_get_mem(kinfo)); + if ( ret ) + goto err; + +#ifdef CONFIG_STATIC_SHM + ret =3D make_resv_memory_node(kinfo, addrcells, sizecells); + if ( ret ) + goto err; +#endif + + /* + * 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_intc. + */ + if ( kinfo->dtb_bootmodule ) + { + ret =3D domain_handle_dtb_bootmodule(d, kinfo); + if ( ret ) + goto err; + } + + ret =3D make_intc_domU_node(kinfo); + if ( ret ) + goto err; + + ret =3D make_timer_node(kinfo); + 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 make_arch_nodes(kinfo); + 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; +} + +#define XENSTORE_PFN_OFFSET 1 +static int __init alloc_xenstore_page(struct domain *d) +{ + struct page_info *xenstore_pg; + struct xenstore_domain_interface *interface; + mfn_t mfn; + gfn_t gfn; + int rc; + + if ( (UINT_MAX - d->max_pages) < 1 ) + { + printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages by 1 page= .\n", + d); + return -EINVAL; + } + + d->max_pages +=3D 1; + xenstore_pg =3D alloc_domheap_page(d, MEMF_bits(32)); + if ( xenstore_pg =3D=3D NULL && is_64bit_domain(d) ) + xenstore_pg =3D alloc_domheap_page(d, 0); + if ( xenstore_pg =3D=3D NULL ) + return -ENOMEM; + + mfn =3D page_to_mfn(xenstore_pg); + if ( !mfn_x(mfn) ) + return -ENOMEM; + + if ( !is_domain_direct_mapped(d) ) + gfn =3D gaddr_to_gfn(GUEST_MAGIC_BASE + + (XENSTORE_PFN_OFFSET << PAGE_SHIFT)); + else + gfn =3D gaddr_to_gfn(mfn_to_maddr(mfn)); + + rc =3D guest_physmap_add_page(d, gfn, mfn, 0); + if ( rc ) + { + free_domheap_page(xenstore_pg); + return rc; + } + +#ifdef CONFIG_HVM + d->arch.hvm.params[HVM_PARAM_STORE_PFN] =3D gfn_x(gfn); +#endif + interface =3D map_domain_page(mfn); + interface->connection =3D XENSTORE_RECONNECT; + unmap_domain_page(interface); + + return 0; +} + +static int __init alloc_xenstore_params(struct kernel_info *kinfo) +{ + struct domain *d =3D kinfo->d; + int rc =3D 0; + +#ifdef CONFIG_HVM + if ( (kinfo->dom0less_feature & (DOM0LESS_XENSTORE | DOM0LESS_XS_LEGAC= Y)) + =3D=3D (DOM0LESS_XENSTORE | DOM0LESS_XS_L= EGACY) ) + d->arch.hvm.params[HVM_PARAM_STORE_PFN] =3D XENSTORE_PFN_LATE_ALLO= C; + else +#endif + if ( kinfo->dom0less_feature & DOM0LESS_XENSTORE ) + { + rc =3D alloc_xenstore_page(d); + if ( rc < 0 ) + return rc; + } + + return rc; +} + +static void __init domain_vcpu_affinity(struct domain *d, + const struct dt_device_node *node) +{ + struct dt_device_node *np; + + dt_for_each_child_node(node, np) + { + const char *hard_affinity_str =3D NULL; + uint32_t val; + int rc; + struct vcpu *v; + cpumask_t affinity; + + if ( !dt_device_is_compatible(np, "xen,vcpu") ) + continue; + + if ( !dt_property_read_u32(np, "id", &val) ) + panic("Invalid xen,vcpu node for domain %s\n", dt_node_name(no= de)); + + if ( val >=3D d->max_vcpus ) + panic("Invalid vcpu_id %u for domain %s, max_vcpus=3D%u\n", va= l, + dt_node_name(node), d->max_vcpus); + + v =3D d->vcpu[val]; + rc =3D dt_property_read_string(np, "hard-affinity", &hard_affinity= _str); + if ( rc < 0 ) + continue; + + cpumask_clear(&affinity); + while ( *hard_affinity_str !=3D '\0' ) + { + unsigned int start, end; + + start =3D simple_strtoul(hard_affinity_str, &hard_affinity_str= , 0); + + if ( *hard_affinity_str =3D=3D '-' ) /* Range */ + { + hard_affinity_str++; + end =3D simple_strtoul(hard_affinity_str, &hard_affinity_s= tr, 0); + } + else /* Single value */ + end =3D start; + + if ( end >=3D nr_cpu_ids ) + panic("Invalid pCPU %u for domain %s\n", end, dt_node_name= (node)); + + for ( ; start <=3D end; start++ ) + cpumask_set_cpu(start, &affinity); + + if ( *hard_affinity_str =3D=3D ',' ) + hard_affinity_str++; + else if ( *hard_affinity_str !=3D '\0' ) + break; + } + + rc =3D vcpu_set_hard_affinity(v, &affinity); + if ( rc ) + panic("vcpu%d: failed (rc=3D%d) to set hard affinity for domai= n %s\n", + v->vcpu_id, rc, dt_node_name(node)); + } +} + +#ifdef CONFIG_ARCH_PAGING_MEMPOOL +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 domain_p2m_set_allocation(struct domain *d, uint64_t mem, + const struct dt_device_node *n= ode) +{ + unsigned long p2m_pages; + uint32_t p2m_mem_mb; + int rc; + + 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); + + return rc; +} +#else /* !CONFIG_ARCH_PAGING_MEMPOOL */ +static inline int domain_p2m_set_allocation(struct domain *d, uint64_t mem, + const struct dt_device_node *n= ode) +{ + return 0; +} +#endif /* CONFIG_ARCH_PAGING_MEMPOOL */ + +static int __init construct_domU(struct domain *d, + const struct dt_device_node *node) +{ + struct kernel_info kinfo =3D KERNEL_INFO_INIT; + const char *dom0less_enhanced; + int rc; + u64 mem; + + 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 domain_p2m_set_allocation(d, mem, node); + if ( rc !=3D 0 ) + return rc; + + printk("*** LOADING DOMU cpus=3D%u memory=3D%#"PRIx64"KB ***\n", + d->max_vcpus, mem); + + 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")) ) + { + need_xenstore =3D true; + kinfo.dom0less_feature =3D DOM0LESS_ENHANCED; + } + else if ( rc =3D=3D 0 && !strcmp(dom0less_enhanced, "legacy") ) + { + need_xenstore =3D true; + kinfo.dom0less_feature =3D DOM0LESS_ENHANCED_LEGACY; + } + 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; + + set_domain_type(d, &kinfo); + + if ( !dt_find_property(node, "xen,static-mem", NULL) ) + allocate_memory(d, &kinfo); +#ifdef CONFIG_STATIC_MEMORY + else if ( !is_domain_direct_mapped(d) ) + allocate_static_memory(d, &kinfo, node); + else + assign_static_memory_11(d, &kinfo, node); +#endif + +#ifdef CONFIG_STATIC_SHM + rc =3D process_shm(d, &kinfo, node); + if ( rc < 0 ) + return rc; +#endif + + rc =3D init_vuart(d, &kinfo, node); + 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; + + domain_vcpu_affinity(d, node); + + return alloc_xenstore_params(&kinfo); +} + void __init create_domUs(void) { struct dt_device_node *node; diff --git a/xen/include/asm-generic/dom0less-build.h b/xen/include/asm-gen= eric/dom0less-build.h index f095135caa..c00bb853d6 100644 --- a/xen/include/asm-generic/dom0less-build.h +++ b/xen/include/asm-generic/dom0less-build.h @@ -11,10 +11,7 @@ =20 struct domain; struct dt_device_node; - -/* TODO: remove both when construct_domU() will be moved to common. */ -#define XENSTORE_PFN_LATE_ALLOC UINT64_MAX -extern bool need_xenstore; +struct kernel_info; =20 /* * List of possible features for dom0less domUs @@ -48,12 +45,21 @@ void create_domUs(void); bool is_dom0less_mode(void); void set_xs_domain(struct domain *d); =20 -int construct_domU(struct domain *d, const struct dt_device_node *node); - void arch_create_domUs(struct dt_device_node *node, struct xen_domctl_createdomain *d_cfg, unsigned int flags); =20 +int init_vuart(struct domain *d, struct kernel_info *kinfo, + const struct dt_device_node *node); + +int make_intc_domU_node(struct kernel_info *kinfo); +int make_arch_nodes(struct kernel_info *kinfo); + +void set_domain_type(struct domain *d, struct kernel_info *kinfo); + +int init_intc_phandle(struct kernel_info *kinfo, const char *name, + const int node_next, const void *pfdt); + #else /* !CONFIG_DOM0LESS_BOOT */ =20 static inline void create_domUs(void) {} --=20 2.49.0