From patchwork Wed May 13 18:33:38 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julien Grall X-Patchwork-Id: 48458 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-lb0-f198.google.com (mail-lb0-f198.google.com [209.85.217.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id D26A92121F for ; Wed, 13 May 2015 18:45:10 +0000 (UTC) Received: by lbbrr5 with SMTP id rr5sf11372556lbb.3 for ; Wed, 13 May 2015 11:45:09 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:in-reply-to :references:mime-version:cc:subject:precedence:list-id :list-unsubscribe:list-post:list-help:list-subscribe:content-type :content-transfer-encoding:sender:errors-to:x-original-sender :x-original-authentication-results:mailing-list:list-archive; bh=i+z/+CZ7knbiLM/uDc7vz1faiAuJ9N/KYIDb4D8V7lw=; b=EO+1lk8klR1oDUbJg04gAEN6fDCOXVSYlEz+lQqahaCnJTEoVYYGHE6uA8as22czhH UewZO2kGhQ/j3lLADwK8VAnVQefBGY4tOsbVaGT57GmTg7Fv62E0yFvzoG+YTFcbH+sD o3xvnwT8qBPCP8ePTdgeMBQMxL2WoK3e1z5JZRKck4eTGEFBGsV0d2ADOxZM+a1GbXTW Hwzcj/6wYb3anGc/M2iXteiZDb4mFnZ0RB4AJK9TmcIx8sNya1sn5TmOnLpakFLnu0H9 12eB1tUU2r2z3rC6wjMP9iuDicShQvpsnlgg1ZLhuCDouG860233V0uLBeVIn2iuVW4S fUKw== X-Gm-Message-State: ALoCoQl5QFttt/u6RudgDqe55Zswt2JzaIgCiEKkmYyPLG8mPnuqWNhGVCdry+JZt6rkoMUI4b0q X-Received: by 10.112.28.111 with SMTP id a15mr171116lbh.21.1431542709343; Wed, 13 May 2015 11:45:09 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.245.43 with SMTP id xl11ls291755lac.21.gmail; Wed, 13 May 2015 11:45:09 -0700 (PDT) X-Received: by 10.152.30.100 with SMTP id r4mr185954lah.107.1431542709232; Wed, 13 May 2015 11:45:09 -0700 (PDT) Received: from mail-la0-f53.google.com (mail-la0-f53.google.com. [209.85.215.53]) by mx.google.com with ESMTPS id ph1si12904717lbb.120.2015.05.13.11.45.09 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 13 May 2015 11:45:09 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.53 as permitted sender) client-ip=209.85.215.53; Received: by layy10 with SMTP id y10so36077364lay.0 for ; Wed, 13 May 2015 11:45:09 -0700 (PDT) X-Received: by 10.152.27.1 with SMTP id p1mr221861lag.112.1431542709071; Wed, 13 May 2015 11:45:09 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.108.230 with SMTP id hn6csp703831lbb; Wed, 13 May 2015 11:45:07 -0700 (PDT) X-Received: by 10.140.150.209 with SMTP id 200mr438687qhw.9.1431542706896; Wed, 13 May 2015 11:45:06 -0700 (PDT) Received: from lists.xen.org (lists.xen.org. [50.57.142.19]) by mx.google.com with ESMTPS id q34si15768849qkq.49.2015.05.13.11.45.06 (version=TLSv1 cipher=RC4-SHA bits=128/128); Wed, 13 May 2015 11:45:06 -0700 (PDT) Received-SPF: none (google.com: xen-devel-bounces@lists.xen.org does not designate permitted sender hosts) client-ip=50.57.142.19; Received: from localhost ([127.0.0.1] helo=lists.xen.org) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1YsbdQ-0001LP-0D; Wed, 13 May 2015 18:44:00 +0000 Received: from mail6.bemta14.messagelabs.com ([193.109.254.103]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1YsbdO-0001Kn-Rw for xen-devel@lists.xenproject.org; Wed, 13 May 2015 18:43:59 +0000 Received: from [193.109.254.147] by server-11.bemta-14.messagelabs.com id 20/38-02795-D6B93555; Wed, 13 May 2015 18:43:57 +0000 X-Env-Sender: julien.grall@citrix.com X-Msg-Ref: server-12.tower-27.messagelabs.com!1431542634!17369534!2 X-Originating-IP: [66.165.176.63] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni42MyA9PiAzMDYwNDg=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 6.13.14; banners=-,-,- X-VirusChecked: Checked Received: (qmail 31679 invoked from network); 13 May 2015 18:43:56 -0000 Received: from smtp02.citrix.com (HELO SMTP02.CITRIX.COM) (66.165.176.63) by server-12.tower-27.messagelabs.com with RC4-SHA encrypted SMTP; 13 May 2015 18:43:56 -0000 X-IronPort-AV: E=Sophos;i="5.13,422,1427760000"; d="scan'208";a="264786303" From: Julien Grall To: Date: Wed, 13 May 2015 19:33:38 +0100 Message-ID: <1431542022-16138-3-git-send-email-julien.grall@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1431542022-16138-1-git-send-email-julien.grall@citrix.com> References: <1431542022-16138-1-git-send-email-julien.grall@citrix.com> MIME-Version: 1.0 X-DLP: MIA1 Cc: Wei Liu , ian.campbell@citrix.com, tim@xen.org, Julien Grall , Ian Jackson , stefano.stabellini@citrix.com Subject: [Xen-devel] [PATCH v9 2/6] tools/(lib)xl: Add partial device tree support for ARM X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: List-Unsubscribe: , List-Post: , List-Help: , List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: patch@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.53 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Archive: From: Julien Grall Allow the user to pass additional nodes to the guest device tree. For this purpose, everything in the node /passthrough from the partial device tree will be copied into the guest device tree. The node /aliases will be also copied to allow the user to define aliases which can be used by the guest kernel. A simple partial device tree will look like: /dts-v1/; / { #address-cells = <2>; #size-cells = <2>; passthrough { compatible = "simple-bus"; ranges; #address-cells = <2>; #size-cells = <2>; /* List of your nodes */ } }; Note that: * The interrupt-parent property will be added by the toolstack in the root node * The properties compatible, ranges, #address-cells and #size-cells in /passthrough are mandatory. The helpers provided by the libfdt don't perform all the necessary security check on a given device tree. Therefore, only trusted device tree should be used. Note: The partial device tree code requires the presence of libfdt functions which have been only correctly exported in libfdt 1.4.0 and higher. All the major distributions but Debian Wheezy are using v1.4.0 or higher. It has been decided to disable partial device tree support on OSes where libfdt doesn't meet the requirement. Signed-off-by: Julien Grall Cc: Ian Jackson Cc: Wei Liu --- An example of the partial device tree, as long as how to passthrough a non-pci device will be added to the tree in a follow-up patch. A new LIBXL_HAVE_* will be added in the patch which add support for non-PCI passthrough as both are tight. Changes in v9: - Drop ack from the 2 Ian's due to build changes - Only enable partial device tree when libfdt > 1.4.0 is present Changes in v7: - Drop declaration of fdt_{first,next}_subnode. They are correctly define in libxl_libfdt_compat.h if necessary Changes in v6: - Fix grammar in the commit message - Spelling mistake the IDL - Add Ian J. and Ian C.'s ack Changes in v5: - Add a warning in the IDL - Remove the requirement to use only the version 17 of the FDT format. Changes in v4: - Mark the option as unsafe - The _fdt_* helpers has been moved in a separate patch/file. Only the prototype is declared - The partial DT is considered valid. Remove some security check which make the code cleaner - Typoes Changes in v3: - Patch added --- docs/man/xl.cfg.pod.5 | 10 +++ tools/configure.ac | 12 +++ tools/libxl/libxl_arm.c | 173 ++++++++++++++++++++++++++++++++++++++++++++ tools/libxl/libxl_types.idl | 4 + tools/libxl/xl_cmdimpl.c | 1 + 5 files changed, 200 insertions(+) diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5 index 8e4154f..ead8a5c 100644 --- a/docs/man/xl.cfg.pod.5 +++ b/docs/man/xl.cfg.pod.5 @@ -460,6 +460,16 @@ not emulated. Specify that this domain is a driver domain. This enables certain features needed in order to run a driver domain. +=item B + +Specify a partial device tree (compiled via the Device Tree Compiler). +Everything under the node "/passthrough" will be copied into the guest +device tree. For convenience, the node "/aliases" is also copied to allow +the user to defined aliases which can be used by the guest kernel. + +Given the complexity of verifying the validity of a device tree, this +option should only be used with trusted device tree. + =back =head2 Devices diff --git a/tools/configure.ac b/tools/configure.ac index 5b48ab2..58b6caa 100644 --- a/tools/configure.ac +++ b/tools/configure.ac @@ -356,6 +356,18 @@ case "$host_cpu" in arm*|aarch64) AC_CHECK_LIB([fdt], [fdt_create], [], [AC_MSG_ERROR([Could not find libfdt])]) +# Check for libfdt >= 1.4.0. If present enable passthrough +# Note that libfdt doesn't provide versionning. So we need to rely on +# function present in new version. +# Use fdt_first_property_offset which has been correctly exported since v1.4.0 +AC_CHECK_FUNC(fdt_first_property_offset, [partial_dt="y"], [partial_dt="n"]) + +AS_IF([test "x$partial_dt" = "xy" ], + [AC_DEFINE([ENABLE_PARTIAL_DEVICE_TREE], [1], + [Enabling support partial device tree in libxl])], + [AC_MSG_WARN([Disabling support for partial device tree in libxl. + Please install libfdt library - version 1.4.0 or higher])]) + # The functions fdt_{first,next}_subnode may not be available because: # * It has been introduced in 2013 => Doesn't work on Wheezy # * The prototype exists but the functions are not exposed. Don't ask why... diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c index feded58..71dbb9e 100644 --- a/tools/libxl/libxl_arm.c +++ b/tools/libxl/libxl_arm.c @@ -1,5 +1,6 @@ #include "libxl_internal.h" #include "libxl_arch.h" +#include "libxl_libfdt_compat.h" #include #include @@ -542,6 +543,157 @@ out: } } +#ifdef ENABLE_PARTIAL_DEVICE_TREE + +static int check_partial_fdt(libxl__gc *gc, void *fdt, size_t size) +{ + int r; + + if (fdt_magic(fdt) != FDT_MAGIC) { + LOG(ERROR, "Partial FDT is not a valid Flat Device Tree"); + return ERROR_FAIL; + } + + r = fdt_check_header(fdt); + if (r) { + LOG(ERROR, "Failed to check the partial FDT (%d)", r); + return ERROR_FAIL; + } + + if (fdt_totalsize(fdt) > size) { + LOG(ERROR, "Partial FDT totalsize is too big"); + return ERROR_FAIL; + } + + return 0; +} + +static int copy_properties(libxl__gc *gc, void *fdt, void *pfdt, + int nodeoff) +{ + int propoff, nameoff, r; + 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); + r = fdt_property(fdt, fdt_string(pfdt, nameoff), + prop->data, fdt32_to_cpu(prop->len)); + if (r) return r; + } + + /* FDT_ERR_NOTFOUND => There is no more properties for this node */ + return (propoff != -FDT_ERR_NOTFOUND)? propoff : 0; +} + +/* Copy a node from the partial device tree to the guest device tree */ +static int copy_node(libxl__gc *gc, void *fdt, void *pfdt, + int nodeoff, int depth) +{ + int r; + + r = fdt_begin_node(fdt, fdt_get_name(pfdt, nodeoff, NULL)); + if (r) return r; + + r = copy_properties(gc, fdt, pfdt, nodeoff); + if (r) return r; + + for (nodeoff = fdt_first_subnode(pfdt, nodeoff); + nodeoff >= 0; + nodeoff = fdt_next_subnode(pfdt, nodeoff)) { + r = copy_node(gc, fdt, pfdt, nodeoff, depth + 1); + if (r) return r; + } + + if (nodeoff != -FDT_ERR_NOTFOUND) + return nodeoff; + + r = fdt_end_node(fdt); + if (r) return r; + + return 0; +} + +static int copy_node_by_path(libxl__gc *gc, const char *path, + void *fdt, void *pfdt) +{ + int nodeoff, r; + const char *name = strrchr(path, '/'); + + if (!name) + return -FDT_ERR_INTERNAL; + + name++; + + /* + * The FDT function to look at a node doesn't take into account the + * unit (i.e anything after @) when search by name. Check if the + * name exactly matches. + */ + nodeoff = fdt_path_offset(pfdt, path); + if (nodeoff < 0) + return nodeoff; + + if (strcmp(fdt_get_name(pfdt, nodeoff, NULL), name)) + return -FDT_ERR_NOTFOUND; + + r = copy_node(gc, fdt, pfdt, nodeoff, 0); + if (r) return r; + + return 0; +} + +/* + * The partial device tree is not copied entirely. Only the relevant bits are + * copied to the guest device tree: + * - /passthrough node + * - /aliases node + */ +static int copy_partial_fdt(libxl__gc *gc, void *fdt, void *pfdt) +{ + int r; + + r = copy_node_by_path(gc, "/passthrough", fdt, pfdt); + if (r < 0) { + LOG(ERROR, "Can't copy the node \"/passthrough\" from the partial FDT"); + return r; + } + + r = copy_node_by_path(gc, "/aliases", fdt, pfdt); + if (r < 0 && r != -FDT_ERR_NOTFOUND) { + LOG(ERROR, "Can't copy the node \"/aliases\" from the partial FDT"); + return r; + } + + return 0; +} + +#else + +static int check_partial_fdt(libxl__gc *gc, void *fdt, size_t size) +{ + LOG(ERROR, "partial device tree not supported"); + + return ERROR_FAIL; +} + +static int copy_partial_fdt(libxl__gc *gc, void *fdt, void *pfdt) +{ + /* + * We should never be here when the partial device tree is not + * supported. + * */ + return -FDT_ERR_INTERNAL; +} + +#endif /* ENABLE_PARTIAL_DEVICE_TREE */ + #define FDT_MAX_SIZE (1<<20) int libxl__arch_domain_init_hw_description(libxl__gc *gc, @@ -550,8 +702,10 @@ int libxl__arch_domain_init_hw_description(libxl__gc *gc, struct xc_dom_image *dom) { void *fdt = NULL; + void *pfdt = NULL; int rc, res; size_t fdt_size = 0; + int pfdt_size = 0; const libxl_version_info *vers; const struct arch_info *ainfo; @@ -571,6 +725,22 @@ int libxl__arch_domain_init_hw_description(libxl__gc *gc, vers->xen_version_major, vers->xen_version_minor); LOG(DEBUG, " - vGIC version: %s", gicv_to_string(xc_config->gic_version)); + if (info->device_tree) { + LOG(DEBUG, " - Partial device tree provided: %s", info->device_tree); + + rc = libxl_read_file_contents(CTX, info->device_tree, + &pfdt, &pfdt_size); + if (rc) { + LOGEV(ERROR, rc, "failed to read the partial device file %s", + info->device_tree); + return ERROR_FAIL; + } + libxl__ptr_add(gc, pfdt); + + if (check_partial_fdt(gc, pfdt, pfdt_size)) + return ERROR_FAIL; + } + /* * Call "call" handling FDT_ERR_*. Will either: * - loop back to retry_resize @@ -637,6 +807,9 @@ next_resize: FDT( make_timer_node(gc, fdt, ainfo) ); FDT( make_hypervisor_node(gc, fdt, vers) ); + if (pfdt) + FDT( copy_partial_fdt(gc, fdt, pfdt) ); + FDT( fdt_end_node(fdt) ); FDT( fdt_finish(fdt) ); diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 65d479f..4ea1290 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -413,6 +413,10 @@ libxl_domain_build_info = Struct("domain_build_info",[ ("kernel", string), ("cmdline", string), ("ramdisk", string), + # Given the complexity of verifying the validity of a device tree, + # libxl doesn't do any security check on it. It's the responsibility + # of the caller to provide only trusted device tree. + ("device_tree", string), ("u", KeyedUnion(None, libxl_domain_type, "type", [("hvm", Struct(None, [("firmware", string), ("bios", libxl_bios_type), diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 373aa37..2125a09 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -1379,6 +1379,7 @@ static void parse_config_data(const char *config_source, xlu_cfg_replace_string (config, "kernel", &b_info->kernel, 0); xlu_cfg_replace_string (config, "ramdisk", &b_info->ramdisk, 0); + xlu_cfg_replace_string (config, "device_tree", &b_info->device_tree, 0); b_info->cmdline = parse_cmdline(config); xlu_cfg_get_defbool(config, "driver_domain", &c_info->driver_domain, 0);