From patchwork Mon Jun 16 16:17:56 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julien Grall X-Patchwork-Id: 31988 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ie0-f200.google.com (mail-ie0-f200.google.com [209.85.223.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 13E282107C for ; Mon, 16 Jun 2014 16:20:11 +0000 (UTC) Received: by mail-ie0-f200.google.com with SMTP id tr6sf33658702ieb.11 for ; Mon, 16 Jun 2014 09:20:10 -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:cc:subject:precedence:list-id:list-unsubscribe:list-post :list-help:list-subscribe:mime-version:sender:errors-to :x-original-sender:x-original-authentication-results:mailing-list :list-archive:content-type:content-transfer-encoding; bh=bww7zLRm7P6PK99wkUp1A45yhhlz+kAJtounh7r9FJE=; b=HjX3cGkEdt1seGs+27zhu9iOEP/oiEwl3ERaOqMVoqhTyoe2+T66QZ/cJC/k8m7VhX 3YO2HMmy6f66KqMQd9SzwOPoffYDcXh581VaWAeP9YB+2aUfM1K/XGCy3O8JqWJLKxiR Rv2S3d26LDsVGvuT8g17RgTfVK3bog+vB0i55U3cBmbP7ALUIaVdB3k5WY9Qqim4y/SI MNyGThElIdPRVIEDP4oqOc83YCP4X4Zx7jrTD7Y8YA2jRXDnaI1bUq0oEFWzI8qOVN1a 3mFqU/urTEh6Z8fiO2G3FUgfpP7AcTzmD2dq1IiLHq7qJbYzNwPjfvMZ4rEkH7bPtc38 2cOg== X-Gm-Message-State: ALoCoQlOaTZMVbzT/YoDkrkK/d9lOMoEc64uYbB1q8hOOIZ7UKJeh4nI/RYXhzVUO09c7bP1B0CV X-Received: by 10.182.128.234 with SMTP id nr10mr418301obb.0.1402935610480; Mon, 16 Jun 2014 09:20:10 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.24.181 with SMTP id 50ls4410210qgr.92.gmail; Mon, 16 Jun 2014 09:20:10 -0700 (PDT) X-Received: by 10.220.92.135 with SMTP id r7mr17023880vcm.11.1402935610371; Mon, 16 Jun 2014 09:20:10 -0700 (PDT) Received: from mail-ve0-f174.google.com (mail-ve0-f174.google.com [209.85.128.174]) by mx.google.com with ESMTPS id ub7si4291105veb.10.2014.06.16.09.20.10 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 16 Jun 2014 09:20:10 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.128.174 as permitted sender) client-ip=209.85.128.174; Received: by mail-ve0-f174.google.com with SMTP id jx11so3583426veb.33 for ; Mon, 16 Jun 2014 09:20:10 -0700 (PDT) X-Received: by 10.58.216.163 with SMTP id or3mr94358vec.80.1402935610275; Mon, 16 Jun 2014 09:20:10 -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.221.54.6 with SMTP id vs6csp146183vcb; Mon, 16 Jun 2014 09:20:09 -0700 (PDT) X-Received: by 10.224.41.65 with SMTP id n1mr27807305qae.75.1402935608424; Mon, 16 Jun 2014 09:20:08 -0700 (PDT) Received: from lists.xen.org (lists.xen.org. [50.57.142.19]) by mx.google.com with ESMTPS id m8si13821972qai.26.2014.06.16.09.20.08 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Mon, 16 Jun 2014 09:20:08 -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 1WwZc7-0006m6-AB; Mon, 16 Jun 2014 16:18:31 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1WwZc5-0006lC-NI for xen-devel@lists.xenproject.org; Mon, 16 Jun 2014 16:18:30 +0000 Received: from [85.158.137.68:53560] by server-11.bemta-3.messagelabs.com id 38/7F-19438-4D81F935; Mon, 16 Jun 2014 16:18:28 +0000 X-Env-Sender: julien.grall@linaro.org X-Msg-Ref: server-4.tower-31.messagelabs.com!1402935507!10339372!1 X-Originating-IP: [74.125.82.180] X-SpamReason: No, hits=0.5 required=7.0 tests=BODY_RANDOM_LONG X-StarScan-Received: X-StarScan-Version: 6.11.3; banners=-,-,- X-VirusChecked: Checked Received: (qmail 11701 invoked from network); 16 Jun 2014 16:18:27 -0000 Received: from mail-we0-f180.google.com (HELO mail-we0-f180.google.com) (74.125.82.180) by server-4.tower-31.messagelabs.com with RC4-SHA encrypted SMTP; 16 Jun 2014 16:18:27 -0000 Received: by mail-we0-f180.google.com with SMTP id x48so5969071wes.11 for ; Mon, 16 Jun 2014 09:18:27 -0700 (PDT) X-Received: by 10.180.83.200 with SMTP id s8mr28613486wiy.2.1402935507460; Mon, 16 Jun 2014 09:18:27 -0700 (PDT) Received: from belegaer.uk.xensource.com ([185.25.64.249]) by mx.google.com with ESMTPSA id l45sm34836161eep.25.2014.06.16.09.18.26 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 16 Jun 2014 09:18:26 -0700 (PDT) From: Julien Grall To: xen-devel@lists.xenproject.org Date: Mon, 16 Jun 2014 17:17:56 +0100 Message-Id: <1402935486-29136-10-git-send-email-julien.grall@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1402935486-29136-1-git-send-email-julien.grall@linaro.org> References: <1402935486-29136-1-git-send-email-julien.grall@linaro.org> Cc: ian.campbell@citrix.com, Stefano Stabellini , tim@xen.org, Julien Grall , Ian Jackson , stefano.stabellini@citrix.com Subject: [Xen-devel] [RFC 09/19] xen/dts: Add hypercalls to retrieve device node information 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: , MIME-Version: 1.0 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: julien.grall@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.128.174 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: DOM0 doesn't provide a generic way to get information about a device tree node. If we want to do it in userspace, we will have to duplicate the MMIO/IRQ translation from Xen. Therefore, we can let the hypervisor doing the job for us and get nearly all the informations. This new physdev operation will let the toolstack get the IRQ/MMIO regions and the compatible string. Most the device node can be described with only theses 3 items. If we need to add a specific properties, then we will have to implement it in userspace (some idea was to use a configuration file describing the additional properties). The hypercall is divided in 4 parts: - GET_INFO: get the numbers of IRQ/MMIO and the size of the compatible string; - GET_IRQ: get the IRQ by index. If the IRQ is not routable (i.e not an SPIs), the errno will be set to -EINVAL; - GET_MMIO: get the MMIO range by index. If the base and the size of is not page-aligned, the errno will be set to -EINVAL; - GET_COMPAT: get the compatible string All the information will be accessible if the device is not used by Xen and protected by an IOMMU. Signed-off-by: Julien Grall Cc: Ian Jackson Cc: Stefano Stabellini Cc: Ian Campbell --- I'm wondering if we can let the toolstack retrieve device information for every device not used by Xen. This would allow embedded guys using passthrough "easily" when their devices are not under an IOMMU. --- tools/libxc/xc_physdev.c | 129 +++++++++++++++++++++++++++++++++++++++++ tools/libxc/xenctrl.h | 36 ++++++++++++ xen/arch/arm/physdev.c | 16 +++++ xen/common/device_tree.c | 112 +++++++++++++++++++++++++++++++++++ xen/include/public/physdev.h | 40 +++++++++++++ xen/include/xen/device_tree.h | 3 + 6 files changed, 336 insertions(+) diff --git a/tools/libxc/xc_physdev.c b/tools/libxc/xc_physdev.c index cf02d85..405fe78 100644 --- a/tools/libxc/xc_physdev.c +++ b/tools/libxc/xc_physdev.c @@ -108,3 +108,132 @@ int xc_physdev_unmap_pirq(xc_interface *xch, return rc; } +int xc_physdev_dtdev_getinfo(xc_interface *xch, + char *path, + xc_dtdev_info_t *info) +{ + int rc; + size_t size = strlen(path); + struct physdev_dtdev_op op; + DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN); + + if ( xc_hypercall_bounce_pre(xch, path) ) + return -1; + + op.op = PHYSDEVOP_DTDEV_GET_INFO; + op.plen = size; + set_xen_guest_handle(op.path, path); + + rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op)); + + xc_hypercall_bounce_post(xch, path); + + if ( !rc ) + { + info->num_irqs = op.u.info.num_irqs; + info->num_mmios = op.u.info.num_mmios; + info->compat_len = op.u.info.compat_len; + } + + return rc; +} + +int xc_physdev_dtdev_getirq(xc_interface *xch, + char *path, + uint32_t index, + xc_dtdev_irq_t *irq) +{ + int rc; + size_t size = strlen(path); + struct physdev_dtdev_op op; + DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN); + + if ( xc_hypercall_bounce_pre(xch, path) ) + return -1; + + op.op = PHYSDEVOP_DTDEV_GET_IRQ; + op.plen = size; + op.index = index; + set_xen_guest_handle(op.path, path); + + rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op)); + + xc_hypercall_bounce_post(xch, path); + + if ( !rc ) + { + irq->irq = op.u.irq.irq; + irq->type = op.u.irq.type; + } + + return rc; +} + +int xc_physdev_dtdev_getmmio(xc_interface *xch, + char *path, + uint32_t index, + xc_dtdev_mmio_t *mmio) +{ + int rc; + size_t size = strlen(path); + struct physdev_dtdev_op op; + DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN); + + if ( xc_hypercall_bounce_pre(xch, path) ) + return -1; + + op.op = PHYSDEVOP_DTDEV_GET_MMIO; + op.plen = size; + op.index = index; + set_xen_guest_handle(op.path, path); + + rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op)); + + xc_hypercall_bounce_post(xch, path); + + if ( !rc ) + { + mmio->mfn = op.u.mmio.mfn; + mmio->nr_mfn = op.u.mmio.nr_mfn; + } + + return rc; +} + +int xc_physdev_dtdev_getcompat(xc_interface *xch, + char *path, + char *compat, + uint32_t *clen) +{ + int rc; + size_t size = strlen(path); + struct physdev_dtdev_op op; + DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN); + DECLARE_HYPERCALL_BOUNCE(compat, *clen, XC_HYPERCALL_BUFFER_BOUNCE_OUT); + + if ( xc_hypercall_bounce_pre(xch, path) ) + return -1; + + rc = -1; + if ( xc_hypercall_bounce_pre(xch, compat) ) + goto out; + + op.op = PHYSDEVOP_DTDEV_GET_COMPAT; + op.plen = size; + set_xen_guest_handle(op.path, path); + + op.u.compat.clen = *clen; + set_xen_guest_handle(op.u.compat.compat, compat); + + rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op)); + + if ( !rc ) + *clen = op.u.compat.clen; + + xc_hypercall_bounce_post(xch, compat); + +out: + xc_hypercall_bounce_post(xch, path); + + return rc; +} diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index b55d857..5ad2d65 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -1143,6 +1143,42 @@ int xc_physdev_pci_access_modify(xc_interface *xch, int func, int enable); +typedef struct xc_dtdev_info { + uint32_t num_irqs; + uint32_t num_mmios; + uint32_t compat_len; +} xc_dtdev_info_t; + +int xc_physdev_dtdev_getinfo(xc_interface *xch, + char *path, + xc_dtdev_info_t *info); + +typedef struct xc_dtdev_irq { + uint32_t irq; + /* TODO: Maybe an enum here? */ + uint32_t type; +} xc_dtdev_irq_t; + +int xc_physdev_dtdev_getirq(xc_interface *xch, + char *path, + uint32_t index, + xc_dtdev_irq_t *irq); + +typedef struct xc_dtdev_mmio { + uint64_t mfn; + uint64_t nr_mfn; +} xc_dtdev_mmio_t; + +int xc_physdev_dtdev_getmmio(xc_interface *xch, + char *path, + uint32_t index, + xc_dtdev_mmio_t *mmio); + +int xc_physdev_dtdev_getcompat(xc_interface *xch, + char *path, + char *compat, + uint32_t *clen); + int xc_readconsolering(xc_interface *xch, char *buffer, unsigned int *pnr_chars, diff --git a/xen/arch/arm/physdev.c b/xen/arch/arm/physdev.c index d17589c..11c5b59 100644 --- a/xen/arch/arm/physdev.c +++ b/xen/arch/arm/physdev.c @@ -82,6 +82,22 @@ int do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) ret = -EFAULT; } break; + + case PHYSDEVOP_dtdev_op: + { + physdev_dtdev_op_t info; + + ret = -EFAULT; + if ( copy_from_guest(&info, arg, 1) != 0 ) + break; + + /* TODO: Add xsm */ + ret = dt_do_physdev_op(&info); + + if ( __copy_to_guest(arg, &info, 1) ) + ret = -EFAULT; + } + break; default: ret = -ENOSYS; break; diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index fd95307..482ff8f 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -24,6 +24,7 @@ #include #include #include +#include struct dt_early_info __initdata early_info; const void *device_tree_flattened; @@ -2021,6 +2022,117 @@ void __init dt_unflatten_host_device_tree(void) dt_alias_scan(); } + +/* TODO: I think we need a bit of caching in each device node to get the + * information in constant time. + * For now we need to translate IRQs/MMIOs every time + */ +int dt_do_physdev_op(physdev_dtdev_op_t *info) +{ + struct dt_device_node *dev; + int ret; + + ret = dt_find_node_by_gpath(info->path, info->plen, &dev); + if ( ret ) + return ret; + + /* Only allow access to protected device and not used by Xen */ + if ( !dt_device_is_protected(dev) || dt_device_used_by(dev) == DOMID_XEN ) + return -EACCES; + + switch ( info->op ) + { + case PHYSDEVOP_DTDEV_GET_INFO: + { + const struct dt_property *compat; + + compat = dt_find_property(dev, "compatible", NULL); + /* Hopefully, this case should never happen, print error + * if it occurs + */ + if ( !compat ) + { + dprintk(XENLOG_G_ERR, "Unable to find compatible node for %s\n", + dt_node_full_name(dev)); + return -EBADFD; + } + + info->u.info.num_irqs = dt_number_of_irq(dev); + info->u.info.num_mmios = dt_number_of_address(dev); + info->u.info.compat_len = compat->length; + } + break; + + case PHYSDEVOP_DTDEV_GET_IRQ: + { + struct dt_irq irq; + + ret = dt_device_get_irq(dev, info->index, &irq); + if ( ret ) + return ret; + + /* Check if Xen is able to route the IRQ to the guest */ + if ( !is_routable_irq(irq.irq) ) + return -EINVAL; + + info->u.irq.irq = irq.irq; + /* TODO: Translate the type into an exportable value */ + info->u.irq.type = irq.type; + } + break; + + case PHYSDEVOP_DTDEV_GET_MMIO: + { + uint64_t addr, size; + + ret = dt_device_get_address(dev, info->index, &addr, &size); + if ( ret ) + return ret; + + /* Make sure the address and the size are page aligned. + * If not, we may passthrough MMIO regions which may belong + * to another device. Deny it! + */ + if ( (addr & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) + { + dprintk(XENLOG_ERR, "%s: contain non-page aligned range:" + " addr = 0x%"PRIx64" size = 0x%"PRIx64"\n", + dt_node_full_name(dev), addr, size); + return -EINVAL; + } + + info->u.mmio.mfn = paddr_to_pfn(addr); + info->u.mmio.nr_mfn = paddr_to_pfn(size); + } + break; + + case PHYSDEVOP_DTDEV_GET_COMPAT: + { + const struct dt_property *compat; + + compat = dt_find_property(dev, "compatible", NULL); + if ( !compat || !compat->length ) + return -ENOENT; + + if ( info->u.compat.clen < compat->length ) + return -ENOSPC; + + if ( copy_to_guest(info->u.compat.compat, compat->value, + compat->length) != 0 ) + return -EFAULT; + + info->u.compat.clen = compat->length; + } + break; + + default: + return -ENOSYS; + } + + + return 0; +} + /* * Local variables: * mode: C diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h index d547928..23cf673 100644 --- a/xen/include/public/physdev.h +++ b/xen/include/public/physdev.h @@ -337,6 +337,46 @@ struct physdev_dbgp_op { typedef struct physdev_dbgp_op physdev_dbgp_op_t; DEFINE_XEN_GUEST_HANDLE(physdev_dbgp_op_t); +/* Retrieve informations about a device node */ +#define PHYSDEVOP_dtdev_op 32 + +struct physdev_dtdev_op { + /* IN */ + uint32_t plen; /* Length of the path */ + XEN_GUEST_HANDLE(char) path; /* Path to the device tree node */ +#define PHYSDEVOP_DTDEV_GET_INFO 0 +#define PHYSDEVOP_DTDEV_GET_IRQ 1 +#define PHYSDEVOP_DTDEV_GET_MMIO 2 +#define PHYSDEVOP_DTDEV_GET_COMPAT 3 + uint8_t op; + uint32_t pad0:24; + uint32_t index; /* Index for the IRQ/MMIO to retrieve */ + /* OUT */ + union { + struct { + uint32_t num_irqs; /* Number of IRQs */ + uint32_t num_mmios; /* Number of MMIOs */ + uint32_t compat_len; /* Length of the compatible string */ + } info; + struct { + /* TODO: Do we need to handle MSI-X? */ + uint32_t irq; /* IRQ number */ + /* TODO: Describe with defines the IRQ type */ + uint32_t type; /* IRQ type (i.e edge, level...) */ + } irq; + struct { + uint64_t mfn; + uint64_t nr_mfn; + } mmio; + struct { + uint32_t clen; /* IN: Size of buffer. OUT: Size copied */ + XEN_GUEST_HANDLE_64(char) compat; + } compat; + } u; +}; +typedef struct physdev_dtdev_op physdev_dtdev_op_t; +DEFINE_XEN_GUEST_HANDLE(physdev_dtdev_op_t); + /* * Notify that some PIRQ-bound event channels have been unmasked. * ** This command is obsolete since interface version 0x00030202 and is ** diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index bb33e54..3d5101c 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -711,6 +712,8 @@ int dt_parse_phandle_with_args(const struct dt_device_node *np, const char *cells_name, int index, struct dt_phandle_args *out_args); +int dt_do_physdev_op(physdev_dtdev_op_t *info); + #endif /* __XEN_DEVICE_TREE_H */ /*