From patchwork Wed Aug 21 03:53:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefano Stabellini X-Patchwork-Id: 11105343 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 938261805 for ; Wed, 21 Aug 2019 03:54:58 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7025922CF7 for ; Wed, 21 Aug 2019 03:54:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=kernel.org header.i=@kernel.org header.b="2oPPUZie" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7025922CF7 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=kernel.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i0Hgi-0007ar-0Y; Wed, 21 Aug 2019 03:53:32 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1i0Hgg-0007a2-2U for xen-devel@lists.xen.org; Wed, 21 Aug 2019 03:53:30 +0000 X-Inumbo-ID: 36e35fd8-c3c7-11e9-8980-bc764e2007e4 Received: from mail.kernel.org (unknown [198.145.29.99]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 36e35fd8-c3c7-11e9-8980-bc764e2007e4; Wed, 21 Aug 2019 03:53:20 +0000 (UTC) Received: from localhost.localdomain (c-67-164-102-47.hsd1.ca.comcast.net [67.164.102.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 22B7E2339E; Wed, 21 Aug 2019 03:53:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1566359599; bh=s9Frwg46jacUxpsDb3kqwBKhlP+4wDLXJFA0JPCWIA4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=2oPPUZieQ/nNxVh+8fug0KOJ0LY9YYWvF3jSfB3JAia42SoITGRVVNzjGhX9h4joH N0z1uEBOO3mlrA9JLMnbbKfOFwKNczwEhU0YRtbKcNsdiVkebgnwPBpIdnNH4Yy5Qz JUgDvnkC3KNQldZiW84fKyt7epvBWhH9ywcDS0WE= From: Stefano Stabellini To: julien.grall@arm.com Date: Tue, 20 Aug 2019 20:53:11 -0700 Message-Id: <20190821035315.12812-4-sstabellini@kernel.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: Subject: [Xen-devel] [PATCH v4 4/8] xen/arm: copy dtb fragment to guest dtb X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , sstabellini@kernel.org, andrii_anisov@epam.com, Achin.Gupta@arm.com, xen-devel@lists.xen.org, Volodymyr_Babchuk@epam.com MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" Read the dtb fragment corresponding to a passthrough device from memory at the location referred to by the "multiboot,device-tree" compatible node. Add a new field named dtb_bootmodule to struct kernel_info to keep track of the dtb fragment location. Copy the fragment to the guest dtb (only /aliases and /passthrough). Set kinfo->guest_phandle_gic based on the phandle of the special "/gic" node in the device tree fragment. "/gic" is a dummy node in the dtb fragment that represents the gic interrupt controller. Other properties in the dtb fragment might refer to it (for instance interrupt-parent of a device node). We reuse the phandle of "/gic" from the dtb fragment as the phandle of the full GIC node that will be created for the guest device tree. That way, when we copy properties from the device tree fragment to the domU device tree the links remain unbroken. Some of the code below is taken from tools/libxl/libxl_arm.c. Note that it is OK to take LGPL 2.1 code and including it into a GPLv2 code base. The result is GPLv2 code. Signed-off-by: Stefano Stabellini ---- Changes in v4: - use recursion in the implementation - rename handle_properties to handle_prop_pfdt - rename scan_pt_node to scan_pfdt_node - pass kinfo to handle_properties - use uint32_t instead of u32 - rename r to res - add "passthrough" and "aliases" check - add a name == NULL check - code style - move DTB fragment scanning earlier, before DomU GIC node creation - set guest_phandle_gic based on "/gic" - in-code comment Changes in v3: - switch to using device_tree_for_each_node for the copy Changes in v2: - add a note about the code coming from libxl in the commit message - copy /aliases - code style --- xen/arch/arm/domain_build.c | 112 +++++++++++++++++++++++++++++++++++ xen/include/asm-arm/kernel.h | 2 +- 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index cd585f05ca..c71b9f2889 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1713,6 +1714,111 @@ static int __init make_vpl011_uart_node(struct kernel_info *kinfo) } #endif +static int __init handle_prop_pfdt(struct kernel_info *kinfo, + const void *pfdt, int nodeoff, + uint32_t address_cells, uint32_t size_cells) +{ + void *fdt = kinfo->fdt; + int propoff, nameoff, res; + const struct fdt_property *prop; + + for ( propoff = fdt_first_property_offset(pfdt, nodeoff); + propoff >= 0; + propoff = fdt_next_property_offset(pfdt, propoff) ) + { + if ( !(prop = fdt_get_property_by_offset(pfdt, propoff, NULL)) ) + return -FDT_ERR_INTERNAL; + + nameoff = fdt32_to_cpu(prop->nameoff); + res = fdt_property(fdt, fdt_string(pfdt, nameoff), + prop->data, fdt32_to_cpu(prop->len)); + if ( res ) + return res; + } + + /* FDT_ERR_NOTFOUND => There is no more properties for this node */ + return ( propoff != -FDT_ERR_NOTFOUND ) ? propoff : 0; +} + +static int __init scan_pfdt_node(struct kernel_info *kinfo, const void *pfdt, + int nodeoff, int depth, + uint32_t address_cells, uint32_t size_cells) +{ + int rc = 0; + void *fdt = kinfo->fdt; + int node_next; + const char *name = fdt_get_name(pfdt, nodeoff, NULL); + + /* + * Take the GIC phandle value from the special /gic node in the DTB + * fragment. + */ + if ( depth == 1 && dt_node_cmp(name, "gic") == 0 ) + { + kinfo->guest_phandle_gic = fdt_get_phandle(pfdt, nodeoff); + return 0; + } + + rc = fdt_begin_node(fdt, fdt_get_name(pfdt, nodeoff, NULL)); + if ( rc ) + return rc; + + rc = handle_prop_pfdt(kinfo, pfdt, nodeoff, address_cells, size_cells); + if ( rc ) + return rc; + + address_cells = device_tree_get_u32(pfdt, nodeoff, "#address-cells", + address_cells); + size_cells = device_tree_get_u32(pfdt, nodeoff, "#size-cells", + size_cells); + + node_next = fdt_first_subnode(pfdt, nodeoff); + while ( node_next > 0 ) + { + scan_pfdt_node(kinfo, pfdt, node_next, depth + 1, address_cells, size_cells); + node_next = fdt_next_subnode(pfdt, node_next); + } + + return fdt_end_node(fdt); +} + +static int __init domain_handle_dtb_bootmodule(struct domain *d, + struct kernel_info *kinfo) +{ + void *pfdt; + int res, node_next; + + pfdt = ioremap_cache(kinfo->dtb_bootmodule->start, + kinfo->dtb_bootmodule->size); + if ( pfdt == NULL ) + return -EFAULT; + + node_next = fdt_first_subnode(pfdt, 0); + while ( node_next > 0 ) + { + const char *name = fdt_get_name(pfdt, node_next, NULL); + + /* only scan /gic /aliases /passthrough, ignore the rest */ + if ( name != NULL && + (dt_node_cmp(name, "passthrough") == 0 || + dt_node_cmp(name, "aliases") == 0 || + dt_node_cmp(name, "gic") == 0) ) + { + res = scan_pfdt_node(kinfo, pfdt, node_next, 1, + DT_ROOT_NODE_ADDR_CELLS_DEFAULT, + DT_ROOT_NODE_SIZE_CELLS_DEFAULT); + if ( res ) + return res; + } + + node_next = fdt_next_subnode(pfdt, node_next); + } + + iounmap(pfdt); + + return res; +} + /* * The max size for DT is 2MB. However, the generated DT is small, 4KB * are enough for now, but we might have to increase it in the future. @@ -1768,6 +1874,12 @@ static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *kinfo) if ( ret ) goto err; + if ( kinfo->dtb_bootmodule ) { + ret = domain_handle_dtb_bootmodule(d, kinfo); + if ( ret ) + return ret; + } + ret = make_gic_domU_node(kinfo); if ( ret ) goto err; diff --git a/xen/include/asm-arm/kernel.h b/xen/include/asm-arm/kernel.h index 760434369b..7f5e659561 100644 --- a/xen/include/asm-arm/kernel.h +++ b/xen/include/asm-arm/kernel.h @@ -28,7 +28,7 @@ struct kernel_info { paddr_t gnttab_size; /* boot blob load addresses */ - const struct bootmodule *kernel_bootmodule, *initrd_bootmodule; + const struct bootmodule *kernel_bootmodule, *initrd_bootmodule, *dtb_bootmodule; const char* cmdline; paddr_t dtb_paddr; paddr_t initrd_paddr;