From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932619AbeE3XMq (ORCPT ); Wed, 30 May 2018 19:12:46 -0400 Received: from mga09.intel.com ([134.134.136.24]:37730 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753695AbeE3XMn (ORCPT ); Wed, 30 May 2018 19:12:43 -0400 X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,461,1520924400"; d="scan'208";a="52058624" Date: Wed, 30 May 2018 16:10:06 -0700 From: Dongwon Kim To: Oleksandr Andrushchenko Cc: xen-devel@lists.xenproject.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, jgross@suse.com, boris.ostrovsky@oracle.com, konrad.wilk@oracle.com, daniel.vetter@intel.com, matthew.d.roper@intel.com, Oleksandr Andrushchenko Subject: Re: [PATCH 6/8] xen/gntdev: Implement dma-buf export functionality Message-ID: <20180530231006.GA2929@downor-Z87X-UD5H> References: <20180525153331.31188-1-andr2000@gmail.com> <20180525153331.31188-7-andr2000@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20180525153331.31188-7-andr2000@gmail.com> User-Agent: Mutt/1.5.24 (2015-08-30) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Fri, May 25, 2018 at 06:33:29PM +0300, Oleksandr Andrushchenko wrote: > From: Oleksandr Andrushchenko > > 1. Create a dma-buf from grant references provided by the foreign > domain. By default dma-buf is backed by system memory pages, but > by providing GNTDEV_DMA_FLAG_XXX flags it can also be created > as a DMA write-combine/coherent buffer, e.g. allocated with > corresponding dma_alloc_xxx API. > Export the resulting buffer as a new dma-buf. > > 2. Implement waiting for the dma-buf to be released: block until the > dma-buf with the file descriptor provided is released. > If within the time-out provided the buffer is not released then > -ETIMEDOUT error is returned. If the buffer with the file descriptor > does not exist or has already been released, then -ENOENT is returned. > For valid file descriptors this must not be treated as error. > > Signed-off-by: Oleksandr Andrushchenko > --- > drivers/xen/gntdev.c | 478 ++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 476 insertions(+), 2 deletions(-) > > diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c > index 9e450622af1a..52abc6cd5846 100644 > --- a/drivers/xen/gntdev.c > +++ b/drivers/xen/gntdev.c > @@ -4,6 +4,8 @@ > * Device for accessing (in user-space) pages that have been granted by other > * domains. > * > + * DMA buffer implementation is based on drivers/gpu/drm/drm_prime.c. > + * > * Copyright (c) 2006-2007, D G Murray. > * (c) 2009 Gerd Hoffmann > * (c) 2018 Oleksandr Andrushchenko, EPAM Systems Inc. > @@ -41,6 +43,9 @@ > #ifdef CONFIG_XEN_GRANT_DMA_ALLOC > #include > #endif > +#ifdef CONFIG_XEN_GNTDEV_DMABUF > +#include > +#endif > > #include > #include > @@ -81,6 +86,17 @@ struct gntdev_priv { > /* Device for which DMA memory is allocated. */ > struct device *dma_dev; > #endif > + > +#ifdef CONFIG_XEN_GNTDEV_DMABUF > + /* Private data of the hyper DMA buffers. */ > + > + /* List of exported DMA buffers. */ > + struct list_head dmabuf_exp_list; > + /* List of wait objects. */ > + struct list_head dmabuf_exp_wait_list; > + /* This is the lock which protects dma_buf_xxx lists. */ > + struct mutex dmabuf_lock; > +#endif > }; > > struct unmap_notify { > @@ -125,12 +141,38 @@ struct grant_map { > > #ifdef CONFIG_XEN_GNTDEV_DMABUF > struct xen_dmabuf { > + struct gntdev_priv *priv; > + struct dma_buf *dmabuf; > + struct list_head next; > + int fd; > + > union { > + struct { > + /* Exported buffers are reference counted. */ > + struct kref refcount; > + struct grant_map *map; > + } exp; > struct { > /* Granted references of the imported buffer. */ > grant_ref_t *refs; > } imp; > } u; > + > + /* Number of pages this buffer has. */ > + int nr_pages; > + /* Pages of this buffer. */ > + struct page **pages; > +}; > + > +struct xen_dmabuf_wait_obj { > + struct list_head next; > + struct xen_dmabuf *xen_dmabuf; > + struct completion completion; > +}; > + > +struct xen_dmabuf_attachment { > + struct sg_table *sgt; > + enum dma_data_direction dir; > }; > #endif > > @@ -320,6 +362,16 @@ static void gntdev_put_map(struct gntdev_priv *priv, struct grant_map *map) > gntdev_free_map(map); > } > > +#ifdef CONFIG_XEN_GNTDEV_DMABUF > +static void gntdev_remove_map(struct gntdev_priv *priv, struct grant_map *map) > +{ > + mutex_lock(&priv->lock); > + list_del(&map->next); > + gntdev_put_map(NULL /* already removed */, map); > + mutex_unlock(&priv->lock); > +} > +#endif > + > /* ------------------------------------------------------------------ */ > > static int find_grant_ptes(pte_t *pte, pgtable_t token, > @@ -628,6 +680,12 @@ static int gntdev_open(struct inode *inode, struct file *flip) > INIT_LIST_HEAD(&priv->freeable_maps); > mutex_init(&priv->lock); > > +#ifdef CONFIG_XEN_GNTDEV_DMABUF > + mutex_init(&priv->dmabuf_lock); > + INIT_LIST_HEAD(&priv->dmabuf_exp_list); > + INIT_LIST_HEAD(&priv->dmabuf_exp_wait_list); > +#endif > + > if (use_ptemod) { > priv->mm = get_task_mm(current); > if (!priv->mm) { > @@ -1053,17 +1111,433 @@ static long gntdev_ioctl_grant_copy(struct gntdev_priv *priv, void __user *u) > /* DMA buffer export support. */ > /* ------------------------------------------------------------------ */ > > +/* ------------------------------------------------------------------ */ > +/* Implementation of wait for exported DMA buffer to be released. */ > +/* ------------------------------------------------------------------ */ > + > +static void dmabuf_exp_release(struct kref *kref); > + > +static struct xen_dmabuf_wait_obj * > +dmabuf_exp_wait_obj_new(struct gntdev_priv *priv, > + struct xen_dmabuf *xen_dmabuf) > +{ > + struct xen_dmabuf_wait_obj *obj; > + > + obj = kzalloc(sizeof(*obj), GFP_KERNEL); > + if (!obj) > + return ERR_PTR(-ENOMEM); > + > + init_completion(&obj->completion); > + obj->xen_dmabuf = xen_dmabuf; > + > + mutex_lock(&priv->dmabuf_lock); > + list_add(&obj->next, &priv->dmabuf_exp_wait_list); > + /* Put our reference and wait for xen_dmabuf's release to fire. */ > + kref_put(&xen_dmabuf->u.exp.refcount, dmabuf_exp_release); > + mutex_unlock(&priv->dmabuf_lock); > + return obj; > +} > + > +static void dmabuf_exp_wait_obj_free(struct gntdev_priv *priv, > + struct xen_dmabuf_wait_obj *obj) > +{ > + struct xen_dmabuf_wait_obj *cur_obj, *q; > + > + mutex_lock(&priv->dmabuf_lock); > + list_for_each_entry_safe(cur_obj, q, &priv->dmabuf_exp_wait_list, next) > + if (cur_obj == obj) { > + list_del(&obj->next); > + kfree(obj); > + break; > + } > + mutex_unlock(&priv->dmabuf_lock); > +} > + > +static int dmabuf_exp_wait_obj_wait(struct xen_dmabuf_wait_obj *obj, > + u32 wait_to_ms) > +{ > + if (wait_for_completion_timeout(&obj->completion, > + msecs_to_jiffies(wait_to_ms)) <= 0) > + return -ETIMEDOUT; > + > + return 0; > +} > + > +static void dmabuf_exp_wait_obj_signal(struct gntdev_priv *priv, > + struct xen_dmabuf *xen_dmabuf) > +{ > + struct xen_dmabuf_wait_obj *obj, *q; > + > + list_for_each_entry_safe(obj, q, &priv->dmabuf_exp_wait_list, next) > + if (obj->xen_dmabuf == xen_dmabuf) { > + pr_debug("Found xen_dmabuf in the wait list, wake\n"); > + complete_all(&obj->completion); > + } > +} > + > +static struct xen_dmabuf * > +dmabuf_exp_wait_obj_get_by_fd(struct gntdev_priv *priv, int fd) > +{ > + struct xen_dmabuf *q, *xen_dmabuf, *ret = ERR_PTR(-ENOENT); > + > + mutex_lock(&priv->dmabuf_lock); > + list_for_each_entry_safe(xen_dmabuf, q, &priv->dmabuf_exp_list, next) > + if (xen_dmabuf->fd == fd) { > + pr_debug("Found xen_dmabuf in the wait list\n"); > + kref_get(&xen_dmabuf->u.exp.refcount); > + ret = xen_dmabuf; > + break; > + } > + mutex_unlock(&priv->dmabuf_lock); > + return ret; > +} > + > static int dmabuf_exp_wait_released(struct gntdev_priv *priv, int fd, > int wait_to_ms) > { > - return -ETIMEDOUT; > + struct xen_dmabuf *xen_dmabuf; > + struct xen_dmabuf_wait_obj *obj; > + int ret; > + > + pr_debug("Will wait for dma-buf with fd %d\n", fd); > + /* > + * Try to find the DMA buffer: if not found means that > + * either the buffer has already been released or file descriptor > + * provided is wrong. > + */ > + xen_dmabuf = dmabuf_exp_wait_obj_get_by_fd(priv, fd); > + if (IS_ERR(xen_dmabuf)) > + return PTR_ERR(xen_dmabuf); > + > + /* > + * xen_dmabuf still exists and is reference count locked by us now, > + * so prepare to wait: allocate wait object and add it to the wait list, > + * so we can find it on release. > + */ > + obj = dmabuf_exp_wait_obj_new(priv, xen_dmabuf); > + if (IS_ERR(obj)) { > + pr_err("Failed to setup wait object, ret %ld\n", PTR_ERR(obj)); > + return PTR_ERR(obj); > + } > + > + ret = dmabuf_exp_wait_obj_wait(obj, wait_to_ms); > + dmabuf_exp_wait_obj_free(priv, obj); > + return ret; > +} > + > +/* ------------------------------------------------------------------ */ > +/* DMA buffer export support. */ > +/* ------------------------------------------------------------------ */ > + > +static struct sg_table * > +dmabuf_pages_to_sgt(struct page **pages, unsigned int nr_pages) > +{ > + struct sg_table *sgt; > + int ret; > + > + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); > + if (!sgt) { > + ret = -ENOMEM; > + goto out; > + } > + > + ret = sg_alloc_table_from_pages(sgt, pages, nr_pages, 0, > + nr_pages << PAGE_SHIFT, > + GFP_KERNEL); > + if (ret) > + goto out; > + > + return sgt; > + > +out: > + kfree(sgt); > + return ERR_PTR(ret); > +} > + > +static int dmabuf_exp_ops_attach(struct dma_buf *dma_buf, > + struct device *target_dev, > + struct dma_buf_attachment *attach) > +{ > + struct xen_dmabuf_attachment *xen_dmabuf_attach; > + > + xen_dmabuf_attach = kzalloc(sizeof(*xen_dmabuf_attach), GFP_KERNEL); > + if (!xen_dmabuf_attach) > + return -ENOMEM; > + > + xen_dmabuf_attach->dir = DMA_NONE; > + attach->priv = xen_dmabuf_attach; > + /* Might need to pin the pages of the buffer now. */ > + return 0; > +} > + > +static void dmabuf_exp_ops_detach(struct dma_buf *dma_buf, > + struct dma_buf_attachment *attach) > +{ > + struct xen_dmabuf_attachment *xen_dmabuf_attach = attach->priv; > + > + if (xen_dmabuf_attach) { > + struct sg_table *sgt = xen_dmabuf_attach->sgt; > + > + if (sgt) { > + if (xen_dmabuf_attach->dir != DMA_NONE) > + dma_unmap_sg_attrs(attach->dev, sgt->sgl, > + sgt->nents, > + xen_dmabuf_attach->dir, > + DMA_ATTR_SKIP_CPU_SYNC); > + sg_free_table(sgt); > + } > + > + kfree(sgt); > + kfree(xen_dmabuf_attach); > + attach->priv = NULL; > + } > + /* Might need to unpin the pages of the buffer now. */ > +} > + > +static struct sg_table * > +dmabuf_exp_ops_map_dma_buf(struct dma_buf_attachment *attach, > + enum dma_data_direction dir) > +{ > + struct xen_dmabuf_attachment *xen_dmabuf_attach = attach->priv; > + struct xen_dmabuf *xen_dmabuf = attach->dmabuf->priv; > + struct sg_table *sgt; > + > + pr_debug("Mapping %d pages for dev %p\n", xen_dmabuf->nr_pages, > + attach->dev); > + > + if (WARN_ON(dir == DMA_NONE || !xen_dmabuf_attach)) > + return ERR_PTR(-EINVAL); > + > + /* Return the cached mapping when possible. */ > + if (xen_dmabuf_attach->dir == dir) > + return xen_dmabuf_attach->sgt; may need to check xen_dmabuf_attach->sgt == NULL (i.e. first time mapping)? Also, I am not sure if this mechanism of reusing previously generated sgt for other mappings is universally ok for any use-cases... I don't know if it is acceptable as per the specification. > + > + /* > + * Two mappings with different directions for the same attachment are > + * not allowed. > + */ > + if (WARN_ON(xen_dmabuf_attach->dir != DMA_NONE)) > + return ERR_PTR(-EBUSY); > + > + sgt = dmabuf_pages_to_sgt(xen_dmabuf->pages, xen_dmabuf->nr_pages); > + if (!IS_ERR(sgt)) { > + if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir, > + DMA_ATTR_SKIP_CPU_SYNC)) { > + sg_free_table(sgt); > + kfree(sgt); > + sgt = ERR_PTR(-ENOMEM); > + } else { > + xen_dmabuf_attach->sgt = sgt; > + xen_dmabuf_attach->dir = dir; > + } > + } > + if (IS_ERR(sgt)) > + pr_err("Failed to map sg table for dev %p\n", attach->dev); > + return sgt; > +} > + > +static void dmabuf_exp_ops_unmap_dma_buf(struct dma_buf_attachment *attach, > + struct sg_table *sgt, > + enum dma_data_direction dir) > +{ > + /* Not implemented. The unmap is done at dmabuf_exp_ops_detach(). */ Not sure if it's ok to do nothing here because the spec says this function is mandatory and it should unmap and "release" &sg_table associated with it. /** * @unmap_dma_buf: * * This is called by dma_buf_unmap_attachment() and should unmap and * release the &sg_table allocated in @map_dma_buf, and it is mandatory. * It should also unpin the backing storage if this is the last mapping * of the DMA buffer, it the exporter supports backing storage * migration. */ > +} > + > +static void dmabuf_exp_release(struct kref *kref) > +{ > + struct xen_dmabuf *xen_dmabuf = > + container_of(kref, struct xen_dmabuf, u.exp.refcount); > + > + dmabuf_exp_wait_obj_signal(xen_dmabuf->priv, xen_dmabuf); > + list_del(&xen_dmabuf->next); > + kfree(xen_dmabuf); > +} > + > +static void dmabuf_exp_ops_release(struct dma_buf *dma_buf) > +{ > + struct xen_dmabuf *xen_dmabuf = dma_buf->priv; > + struct gntdev_priv *priv = xen_dmabuf->priv; > + > + gntdev_remove_map(priv, xen_dmabuf->u.exp.map); > + mutex_lock(&priv->dmabuf_lock); > + kref_put(&xen_dmabuf->u.exp.refcount, dmabuf_exp_release); > + mutex_unlock(&priv->dmabuf_lock); > +} > + > +static void *dmabuf_exp_ops_kmap_atomic(struct dma_buf *dma_buf, > + unsigned long page_num) > +{ > + /* Not implemented. */ > + return NULL; > +} > + > +static void dmabuf_exp_ops_kunmap_atomic(struct dma_buf *dma_buf, > + unsigned long page_num, void *addr) > +{ > + /* Not implemented. */ > +} > + > +static void *dmabuf_exp_ops_kmap(struct dma_buf *dma_buf, > + unsigned long page_num) > +{ > + /* Not implemented. */ > + return NULL; > +} > + > +static void dmabuf_exp_ops_kunmap(struct dma_buf *dma_buf, > + unsigned long page_num, void *addr) > +{ > + /* Not implemented. */ > +} > + > +static int dmabuf_exp_ops_mmap(struct dma_buf *dma_buf, > + struct vm_area_struct *vma) > +{ > + /* Not implemented. */ > + return 0; > +} > + > +static const struct dma_buf_ops dmabuf_exp_ops = { > + .attach = dmabuf_exp_ops_attach, > + .detach = dmabuf_exp_ops_detach, > + .map_dma_buf = dmabuf_exp_ops_map_dma_buf, > + .unmap_dma_buf = dmabuf_exp_ops_unmap_dma_buf, > + .release = dmabuf_exp_ops_release, > + .map = dmabuf_exp_ops_kmap, > + .map_atomic = dmabuf_exp_ops_kmap_atomic, > + .unmap = dmabuf_exp_ops_kunmap, > + .unmap_atomic = dmabuf_exp_ops_kunmap_atomic, > + .mmap = dmabuf_exp_ops_mmap, > +}; > + > +static int dmabuf_export(struct gntdev_priv *priv, struct grant_map *map, > + int *fd) > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct xen_dmabuf *xen_dmabuf; > + int ret = 0; > + > + xen_dmabuf = kzalloc(sizeof(*xen_dmabuf), GFP_KERNEL); > + if (!xen_dmabuf) > + return -ENOMEM; > + > + kref_init(&xen_dmabuf->u.exp.refcount); > + > + xen_dmabuf->priv = priv; > + xen_dmabuf->nr_pages = map->count; > + xen_dmabuf->pages = map->pages; > + xen_dmabuf->u.exp.map = map; > + > + exp_info.exp_name = KBUILD_MODNAME; > + if (map->dma_dev->driver && map->dma_dev->driver->owner) > + exp_info.owner = map->dma_dev->driver->owner; > + else > + exp_info.owner = THIS_MODULE; > + exp_info.ops = &dmabuf_exp_ops; > + exp_info.size = map->count << PAGE_SHIFT; > + exp_info.flags = O_RDWR; > + exp_info.priv = xen_dmabuf; > + > + xen_dmabuf->dmabuf = dma_buf_export(&exp_info); > + if (IS_ERR(xen_dmabuf->dmabuf)) { > + ret = PTR_ERR(xen_dmabuf->dmabuf); > + xen_dmabuf->dmabuf = NULL; > + goto fail; > + } > + > + ret = dma_buf_fd(xen_dmabuf->dmabuf, O_CLOEXEC); > + if (ret < 0) > + goto fail; > + > + xen_dmabuf->fd = ret; > + *fd = ret; > + > + pr_debug("Exporting DMA buffer with fd %d\n", ret); > + > + mutex_lock(&priv->dmabuf_lock); > + list_add(&xen_dmabuf->next, &priv->dmabuf_exp_list); > + mutex_unlock(&priv->dmabuf_lock); > + return 0; > + > +fail: > + if (xen_dmabuf->dmabuf) > + dma_buf_put(xen_dmabuf->dmabuf); > + kfree(xen_dmabuf); > + return ret; > +} > + > +static struct grant_map * > +dmabuf_exp_alloc_backing_storage(struct gntdev_priv *priv, int dmabuf_flags, > + int count) > +{ > + struct grant_map *map; > + > + if (unlikely(count <= 0)) > + return ERR_PTR(-EINVAL); > + > + if ((dmabuf_flags & GNTDEV_DMA_FLAG_WC) && > + (dmabuf_flags & GNTDEV_DMA_FLAG_COHERENT)) { > + pr_err("Wrong dma-buf flags: either WC or coherent, not both\n"); > + return ERR_PTR(-EINVAL); > + } > + > + map = gntdev_alloc_map(priv, count, dmabuf_flags); > + if (!map) > + return ERR_PTR(-ENOMEM); > + > + if (unlikely(atomic_add_return(count, &pages_mapped) > limit)) { > + pr_err("can't map: over limit\n"); > + gntdev_put_map(NULL, map); > + return ERR_PTR(-ENOMEM); > + } > + return map; > } When and how would this allocation be freed? I don't see any ioctl for freeing up shared pages. > > static int dmabuf_exp_from_refs(struct gntdev_priv *priv, int flags, > int count, u32 domid, u32 *refs, u32 *fd) > { > + struct grant_map *map; > + int i, ret; > + > *fd = -1; > - return -EINVAL; > + > + if (use_ptemod) { > + pr_err("Cannot provide dma-buf: use_ptemode %d\n", > + use_ptemod); > + return -EINVAL; > + } > + > + map = dmabuf_exp_alloc_backing_storage(priv, flags, count); > + if (IS_ERR(map)) > + return PTR_ERR(map); > + > + for (i = 0; i < count; i++) { > + map->grants[i].domid = domid; > + map->grants[i].ref = refs[i]; > + } > + > + mutex_lock(&priv->lock); > + gntdev_add_map(priv, map); > + mutex_unlock(&priv->lock); > + > + map->flags |= GNTMAP_host_map; > +#if defined(CONFIG_X86) > + map->flags |= GNTMAP_device_map; > +#endif > + > + ret = map_grant_pages(map); > + if (ret < 0) > + goto out; > + > + ret = dmabuf_export(priv, map, fd); > + if (ret < 0) > + goto out; > + > + return 0; > + > +out: > + gntdev_remove_map(priv, map); > + return ret; > } > > /* ------------------------------------------------------------------ */ > -- > 2.17.0 > From mboxrd@z Thu Jan 1 00:00:00 1970 From: Dongwon Kim Subject: Re: [PATCH 6/8] xen/gntdev: Implement dma-buf export functionality Date: Wed, 30 May 2018 16:10:06 -0700 Message-ID: <20180530231006.GA2929@downor-Z87X-UD5H> References: <20180525153331.31188-1-andr2000@gmail.com> <20180525153331.31188-7-andr2000@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by gabe.freedesktop.org (Postfix) with ESMTPS id 2F18F6E034 for ; Wed, 30 May 2018 23:12:43 +0000 (UTC) Content-Disposition: inline In-Reply-To: <20180525153331.31188-7-andr2000@gmail.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Oleksandr Andrushchenko Cc: jgross@suse.com, konrad.wilk@oracle.com, Oleksandr Andrushchenko , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, daniel.vetter@intel.com, xen-devel@lists.xenproject.org, boris.ostrovsky@oracle.com, linux-media@vger.kernel.org List-Id: dri-devel@lists.freedesktop.org T24gRnJpLCBNYXkgMjUsIDIwMTggYXQgMDY6MzM6MjlQTSArMDMwMCwgT2xla3NhbmRyIEFuZHJ1 c2hjaGVua28gd3JvdGU6Cj4gRnJvbTogT2xla3NhbmRyIEFuZHJ1c2hjaGVua28gPG9sZWtzYW5k cl9hbmRydXNoY2hlbmtvQGVwYW0uY29tPgo+IAo+IDEuIENyZWF0ZSBhIGRtYS1idWYgZnJvbSBn cmFudCByZWZlcmVuY2VzIHByb3ZpZGVkIGJ5IHRoZSBmb3JlaWduCj4gICAgZG9tYWluLiBCeSBk ZWZhdWx0IGRtYS1idWYgaXMgYmFja2VkIGJ5IHN5c3RlbSBtZW1vcnkgcGFnZXMsIGJ1dAo+ICAg IGJ5IHByb3ZpZGluZyBHTlRERVZfRE1BX0ZMQUdfWFhYIGZsYWdzIGl0IGNhbiBhbHNvIGJlIGNy ZWF0ZWQKPiAgICBhcyBhIERNQSB3cml0ZS1jb21iaW5lL2NvaGVyZW50IGJ1ZmZlciwgZS5nLiBh bGxvY2F0ZWQgd2l0aAo+ICAgIGNvcnJlc3BvbmRpbmcgZG1hX2FsbG9jX3h4eCBBUEkuCj4gICAg RXhwb3J0IHRoZSByZXN1bHRpbmcgYnVmZmVyIGFzIGEgbmV3IGRtYS1idWYuCj4gCj4gMi4gSW1w bGVtZW50IHdhaXRpbmcgZm9yIHRoZSBkbWEtYnVmIHRvIGJlIHJlbGVhc2VkOiBibG9jayB1bnRp bCB0aGUKPiAgICBkbWEtYnVmIHdpdGggdGhlIGZpbGUgZGVzY3JpcHRvciBwcm92aWRlZCBpcyBy ZWxlYXNlZC4KPiAgICBJZiB3aXRoaW4gdGhlIHRpbWUtb3V0IHByb3ZpZGVkIHRoZSBidWZmZXIg aXMgbm90IHJlbGVhc2VkIHRoZW4KPiAgICAtRVRJTUVET1VUIGVycm9yIGlzIHJldHVybmVkLiBJ ZiB0aGUgYnVmZmVyIHdpdGggdGhlIGZpbGUgZGVzY3JpcHRvcgo+ICAgIGRvZXMgbm90IGV4aXN0 IG9yIGhhcyBhbHJlYWR5IGJlZW4gcmVsZWFzZWQsIHRoZW4gLUVOT0VOVCBpcyByZXR1cm5lZC4K PiAgICBGb3IgdmFsaWQgZmlsZSBkZXNjcmlwdG9ycyB0aGlzIG11c3Qgbm90IGJlIHRyZWF0ZWQg YXMgZXJyb3IuCj4gCj4gU2lnbmVkLW9mZi1ieTogT2xla3NhbmRyIEFuZHJ1c2hjaGVua28gPG9s ZWtzYW5kcl9hbmRydXNoY2hlbmtvQGVwYW0uY29tPgo+IC0tLQo+ICBkcml2ZXJzL3hlbi9nbnRk ZXYuYyB8IDQ3OCArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKystCj4g IDEgZmlsZSBjaGFuZ2VkLCA0NzYgaW5zZXJ0aW9ucygrKSwgMiBkZWxldGlvbnMoLSkKPiAKPiBk aWZmIC0tZ2l0IGEvZHJpdmVycy94ZW4vZ250ZGV2LmMgYi9kcml2ZXJzL3hlbi9nbnRkZXYuYwo+ IGluZGV4IDllNDUwNjIyYWYxYS4uNTJhYmM2Y2Q1ODQ2IDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMv eGVuL2dudGRldi5jCj4gKysrIGIvZHJpdmVycy94ZW4vZ250ZGV2LmMKPiBAQCAtNCw2ICs0LDgg QEAKPiAgICogRGV2aWNlIGZvciBhY2Nlc3NpbmcgKGluIHVzZXItc3BhY2UpIHBhZ2VzIHRoYXQg aGF2ZSBiZWVuIGdyYW50ZWQgYnkgb3RoZXIKPiAgICogZG9tYWlucy4KPiAgICoKPiArICogRE1B IGJ1ZmZlciBpbXBsZW1lbnRhdGlvbiBpcyBiYXNlZCBvbiBkcml2ZXJzL2dwdS9kcm0vZHJtX3By aW1lLmMuCj4gKyAqCj4gICAqIENvcHlyaWdodCAoYykgMjAwNi0yMDA3LCBEIEcgTXVycmF5Lgo+ ICAgKiAgICAgICAgICAgKGMpIDIwMDkgR2VyZCBIb2ZmbWFubiA8a3JheGVsQHJlZGhhdC5jb20+ Cj4gICAqICAgICAgICAgICAoYykgMjAxOCBPbGVrc2FuZHIgQW5kcnVzaGNoZW5rbywgRVBBTSBT eXN0ZW1zIEluYy4KPiBAQCAtNDEsNiArNDMsOSBAQAo+ICAjaWZkZWYgQ09ORklHX1hFTl9HUkFO VF9ETUFfQUxMT0MKPiAgI2luY2x1ZGUgPGxpbnV4L29mX2RldmljZS5oPgo+ICAjZW5kaWYKPiAr I2lmZGVmIENPTkZJR19YRU5fR05UREVWX0RNQUJVRgo+ICsjaW5jbHVkZSA8bGludXgvZG1hLWJ1 Zi5oPgo+ICsjZW5kaWYKPiAgCj4gICNpbmNsdWRlIDx4ZW4veGVuLmg+Cj4gICNpbmNsdWRlIDx4 ZW4vZ3JhbnRfdGFibGUuaD4KPiBAQCAtODEsNiArODYsMTcgQEAgc3RydWN0IGdudGRldl9wcml2 IHsKPiAgCS8qIERldmljZSBmb3Igd2hpY2ggRE1BIG1lbW9yeSBpcyBhbGxvY2F0ZWQuICovCj4g IAlzdHJ1Y3QgZGV2aWNlICpkbWFfZGV2Owo+ICAjZW5kaWYKPiArCj4gKyNpZmRlZiBDT05GSUdf WEVOX0dOVERFVl9ETUFCVUYKPiArCS8qIFByaXZhdGUgZGF0YSBvZiB0aGUgaHlwZXIgRE1BIGJ1 ZmZlcnMuICovCj4gKwo+ICsJLyogTGlzdCBvZiBleHBvcnRlZCBETUEgYnVmZmVycy4gKi8KPiAr CXN0cnVjdCBsaXN0X2hlYWQgZG1hYnVmX2V4cF9saXN0Owo+ICsJLyogTGlzdCBvZiB3YWl0IG9i amVjdHMuICovCj4gKwlzdHJ1Y3QgbGlzdF9oZWFkIGRtYWJ1Zl9leHBfd2FpdF9saXN0Owo+ICsJ LyogVGhpcyBpcyB0aGUgbG9jayB3aGljaCBwcm90ZWN0cyBkbWFfYnVmX3h4eCBsaXN0cy4gKi8K PiArCXN0cnVjdCBtdXRleCBkbWFidWZfbG9jazsKPiArI2VuZGlmCj4gIH07Cj4gIAo+ICBzdHJ1 Y3QgdW5tYXBfbm90aWZ5IHsKPiBAQCAtMTI1LDEyICsxNDEsMzggQEAgc3RydWN0IGdyYW50X21h cCB7Cj4gIAo+ICAjaWZkZWYgQ09ORklHX1hFTl9HTlRERVZfRE1BQlVGCj4gIHN0cnVjdCB4ZW5f ZG1hYnVmIHsKPiArCXN0cnVjdCBnbnRkZXZfcHJpdiAqcHJpdjsKPiArCXN0cnVjdCBkbWFfYnVm ICpkbWFidWY7Cj4gKwlzdHJ1Y3QgbGlzdF9oZWFkIG5leHQ7Cj4gKwlpbnQgZmQ7Cj4gKwo+ICAJ dW5pb24gewo+ICsJCXN0cnVjdCB7Cj4gKwkJCS8qIEV4cG9ydGVkIGJ1ZmZlcnMgYXJlIHJlZmVy ZW5jZSBjb3VudGVkLiAqLwo+ICsJCQlzdHJ1Y3Qga3JlZiByZWZjb3VudDsKPiArCQkJc3RydWN0 IGdyYW50X21hcCAqbWFwOwo+ICsJCX0gZXhwOwo+ICAJCXN0cnVjdCB7Cj4gIAkJCS8qIEdyYW50 ZWQgcmVmZXJlbmNlcyBvZiB0aGUgaW1wb3J0ZWQgYnVmZmVyLiAqLwo+ICAJCQlncmFudF9yZWZf dCAqcmVmczsKPiAgCQl9IGltcDsKPiAgCX0gdTsKPiArCj4gKwkvKiBOdW1iZXIgb2YgcGFnZXMg dGhpcyBidWZmZXIgaGFzLiAqLwo+ICsJaW50IG5yX3BhZ2VzOwo+ICsJLyogUGFnZXMgb2YgdGhp cyBidWZmZXIuICovCj4gKwlzdHJ1Y3QgcGFnZSAqKnBhZ2VzOwo+ICt9Owo+ICsKPiArc3RydWN0 IHhlbl9kbWFidWZfd2FpdF9vYmogewo+ICsJc3RydWN0IGxpc3RfaGVhZCBuZXh0Owo+ICsJc3Ry dWN0IHhlbl9kbWFidWYgKnhlbl9kbWFidWY7Cj4gKwlzdHJ1Y3QgY29tcGxldGlvbiBjb21wbGV0 aW9uOwo+ICt9Owo+ICsKPiArc3RydWN0IHhlbl9kbWFidWZfYXR0YWNobWVudCB7Cj4gKwlzdHJ1 Y3Qgc2dfdGFibGUgKnNndDsKPiArCWVudW0gZG1hX2RhdGFfZGlyZWN0aW9uIGRpcjsKPiAgfTsK PiAgI2VuZGlmCj4gIAo+IEBAIC0zMjAsNiArMzYyLDE2IEBAIHN0YXRpYyB2b2lkIGdudGRldl9w dXRfbWFwKHN0cnVjdCBnbnRkZXZfcHJpdiAqcHJpdiwgc3RydWN0IGdyYW50X21hcCAqbWFwKQo+ ICAJZ250ZGV2X2ZyZWVfbWFwKG1hcCk7Cj4gIH0KPiAgCj4gKyNpZmRlZiBDT05GSUdfWEVOX0dO VERFVl9ETUFCVUYKPiArc3RhdGljIHZvaWQgZ250ZGV2X3JlbW92ZV9tYXAoc3RydWN0IGdudGRl dl9wcml2ICpwcml2LCBzdHJ1Y3QgZ3JhbnRfbWFwICptYXApCj4gK3sKPiArCW11dGV4X2xvY2so JnByaXYtPmxvY2spOwo+ICsJbGlzdF9kZWwoJm1hcC0+bmV4dCk7Cj4gKwlnbnRkZXZfcHV0X21h cChOVUxMIC8qIGFscmVhZHkgcmVtb3ZlZCAqLywgbWFwKTsKPiArCW11dGV4X3VubG9jaygmcHJp di0+bG9jayk7Cj4gK30KPiArI2VuZGlmCj4gKwo+ICAvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi8KPiAgCj4gIHN0 YXRpYyBpbnQgZmluZF9ncmFudF9wdGVzKHB0ZV90ICpwdGUsIHBndGFibGVfdCB0b2tlbiwKPiBA QCAtNjI4LDYgKzY4MCwxMiBAQCBzdGF0aWMgaW50IGdudGRldl9vcGVuKHN0cnVjdCBpbm9kZSAq aW5vZGUsIHN0cnVjdCBmaWxlICpmbGlwKQo+ICAJSU5JVF9MSVNUX0hFQUQoJnByaXYtPmZyZWVh YmxlX21hcHMpOwo+ICAJbXV0ZXhfaW5pdCgmcHJpdi0+bG9jayk7Cj4gIAo+ICsjaWZkZWYgQ09O RklHX1hFTl9HTlRERVZfRE1BQlVGCj4gKwltdXRleF9pbml0KCZwcml2LT5kbWFidWZfbG9jayk7 Cj4gKwlJTklUX0xJU1RfSEVBRCgmcHJpdi0+ZG1hYnVmX2V4cF9saXN0KTsKPiArCUlOSVRfTElT VF9IRUFEKCZwcml2LT5kbWFidWZfZXhwX3dhaXRfbGlzdCk7Cj4gKyNlbmRpZgo+ICsKPiAgCWlm ICh1c2VfcHRlbW9kKSB7Cj4gIAkJcHJpdi0+bW0gPSBnZXRfdGFza19tbShjdXJyZW50KTsKPiAg CQlpZiAoIXByaXYtPm1tKSB7Cj4gQEAgLTEwNTMsMTcgKzExMTEsNDMzIEBAIHN0YXRpYyBsb25n IGdudGRldl9pb2N0bF9ncmFudF9jb3B5KHN0cnVjdCBnbnRkZXZfcHJpdiAqcHJpdiwgdm9pZCBf X3VzZXIgKnUpCj4gIC8qIERNQSBidWZmZXIgZXhwb3J0IHN1cHBvcnQuICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAqLwo+ICAvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi8KPiAgCj4gKy8q IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLSAqLwo+ICsvKiBJbXBsZW1lbnRhdGlvbiBvZiB3YWl0IGZvciBleHBvcnRlZCBE TUEgYnVmZmVyIHRvIGJlIHJlbGVhc2VkLiAgICAgKi8KPiArLyogLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCj4gKwo+ ICtzdGF0aWMgdm9pZCBkbWFidWZfZXhwX3JlbGVhc2Uoc3RydWN0IGtyZWYgKmtyZWYpOwo+ICsK PiArc3RhdGljIHN0cnVjdCB4ZW5fZG1hYnVmX3dhaXRfb2JqICoKPiArZG1hYnVmX2V4cF93YWl0 X29ial9uZXcoc3RydWN0IGdudGRldl9wcml2ICpwcml2LAo+ICsJCQlzdHJ1Y3QgeGVuX2RtYWJ1 ZiAqeGVuX2RtYWJ1ZikKPiArewo+ICsJc3RydWN0IHhlbl9kbWFidWZfd2FpdF9vYmogKm9iajsK PiArCj4gKwlvYmogPSBremFsbG9jKHNpemVvZigqb2JqKSwgR0ZQX0tFUk5FTCk7Cj4gKwlpZiAo IW9iaikKPiArCQlyZXR1cm4gRVJSX1BUUigtRU5PTUVNKTsKPiArCj4gKwlpbml0X2NvbXBsZXRp b24oJm9iai0+Y29tcGxldGlvbik7Cj4gKwlvYmotPnhlbl9kbWFidWYgPSB4ZW5fZG1hYnVmOwo+ ICsKPiArCW11dGV4X2xvY2soJnByaXYtPmRtYWJ1Zl9sb2NrKTsKPiArCWxpc3RfYWRkKCZvYmot Pm5leHQsICZwcml2LT5kbWFidWZfZXhwX3dhaXRfbGlzdCk7Cj4gKwkvKiBQdXQgb3VyIHJlZmVy ZW5jZSBhbmQgd2FpdCBmb3IgeGVuX2RtYWJ1ZidzIHJlbGVhc2UgdG8gZmlyZS4gKi8KPiArCWty ZWZfcHV0KCZ4ZW5fZG1hYnVmLT51LmV4cC5yZWZjb3VudCwgZG1hYnVmX2V4cF9yZWxlYXNlKTsK PiArCW11dGV4X3VubG9jaygmcHJpdi0+ZG1hYnVmX2xvY2spOwo+ICsJcmV0dXJuIG9iajsKPiAr fQo+ICsKPiArc3RhdGljIHZvaWQgZG1hYnVmX2V4cF93YWl0X29ial9mcmVlKHN0cnVjdCBnbnRk ZXZfcHJpdiAqcHJpdiwKPiArCQkJCSAgICAgc3RydWN0IHhlbl9kbWFidWZfd2FpdF9vYmogKm9i aikKPiArewo+ICsJc3RydWN0IHhlbl9kbWFidWZfd2FpdF9vYmogKmN1cl9vYmosICpxOwo+ICsK PiArCW11dGV4X2xvY2soJnByaXYtPmRtYWJ1Zl9sb2NrKTsKPiArCWxpc3RfZm9yX2VhY2hfZW50 cnlfc2FmZShjdXJfb2JqLCBxLCAmcHJpdi0+ZG1hYnVmX2V4cF93YWl0X2xpc3QsIG5leHQpCj4g KwkJaWYgKGN1cl9vYmogPT0gb2JqKSB7Cj4gKwkJCWxpc3RfZGVsKCZvYmotPm5leHQpOwo+ICsJ CQlrZnJlZShvYmopOwo+ICsJCQlicmVhazsKPiArCQl9Cj4gKwltdXRleF91bmxvY2soJnByaXYt PmRtYWJ1Zl9sb2NrKTsKPiArfQo+ICsKPiArc3RhdGljIGludCBkbWFidWZfZXhwX3dhaXRfb2Jq X3dhaXQoc3RydWN0IHhlbl9kbWFidWZfd2FpdF9vYmogKm9iaiwKPiArCQkJCSAgICB1MzIgd2Fp dF90b19tcykKPiArewo+ICsJaWYgKHdhaXRfZm9yX2NvbXBsZXRpb25fdGltZW91dCgmb2JqLT5j b21wbGV0aW9uLAo+ICsJCQltc2Vjc190b19qaWZmaWVzKHdhaXRfdG9fbXMpKSA8PSAwKQo+ICsJ CXJldHVybiAtRVRJTUVET1VUOwo+ICsKPiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ICtzdGF0aWMg dm9pZCBkbWFidWZfZXhwX3dhaXRfb2JqX3NpZ25hbChzdHJ1Y3QgZ250ZGV2X3ByaXYgKnByaXYs Cj4gKwkJCQkgICAgICAgc3RydWN0IHhlbl9kbWFidWYgKnhlbl9kbWFidWYpCj4gK3sKPiArCXN0 cnVjdCB4ZW5fZG1hYnVmX3dhaXRfb2JqICpvYmosICpxOwo+ICsKPiArCWxpc3RfZm9yX2VhY2hf ZW50cnlfc2FmZShvYmosIHEsICZwcml2LT5kbWFidWZfZXhwX3dhaXRfbGlzdCwgbmV4dCkKPiAr CQlpZiAob2JqLT54ZW5fZG1hYnVmID09IHhlbl9kbWFidWYpIHsKPiArCQkJcHJfZGVidWcoIkZv dW5kIHhlbl9kbWFidWYgaW4gdGhlIHdhaXQgbGlzdCwgd2FrZVxuIik7Cj4gKwkJCWNvbXBsZXRl X2FsbCgmb2JqLT5jb21wbGV0aW9uKTsKPiArCQl9Cj4gK30KPiArCj4gK3N0YXRpYyBzdHJ1Y3Qg eGVuX2RtYWJ1ZiAqCj4gK2RtYWJ1Zl9leHBfd2FpdF9vYmpfZ2V0X2J5X2ZkKHN0cnVjdCBnbnRk ZXZfcHJpdiAqcHJpdiwgaW50IGZkKQo+ICt7Cj4gKwlzdHJ1Y3QgeGVuX2RtYWJ1ZiAqcSwgKnhl bl9kbWFidWYsICpyZXQgPSBFUlJfUFRSKC1FTk9FTlQpOwo+ICsKPiArCW11dGV4X2xvY2soJnBy aXYtPmRtYWJ1Zl9sb2NrKTsKPiArCWxpc3RfZm9yX2VhY2hfZW50cnlfc2FmZSh4ZW5fZG1hYnVm LCBxLCAmcHJpdi0+ZG1hYnVmX2V4cF9saXN0LCBuZXh0KQo+ICsJCWlmICh4ZW5fZG1hYnVmLT5m ZCA9PSBmZCkgewo+ICsJCQlwcl9kZWJ1ZygiRm91bmQgeGVuX2RtYWJ1ZiBpbiB0aGUgd2FpdCBs aXN0XG4iKTsKPiArCQkJa3JlZl9nZXQoJnhlbl9kbWFidWYtPnUuZXhwLnJlZmNvdW50KTsKPiAr CQkJcmV0ID0geGVuX2RtYWJ1ZjsKPiArCQkJYnJlYWs7Cj4gKwkJfQo+ICsJbXV0ZXhfdW5sb2Nr KCZwcml2LT5kbWFidWZfbG9jayk7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICBzdGF0aWMg aW50IGRtYWJ1Zl9leHBfd2FpdF9yZWxlYXNlZChzdHJ1Y3QgZ250ZGV2X3ByaXYgKnByaXYsIGlu dCBmZCwKPiAgCQkJCSAgICBpbnQgd2FpdF90b19tcykKPiAgewo+IC0JcmV0dXJuIC1FVElNRURP VVQ7Cj4gKwlzdHJ1Y3QgeGVuX2RtYWJ1ZiAqeGVuX2RtYWJ1ZjsKPiArCXN0cnVjdCB4ZW5fZG1h YnVmX3dhaXRfb2JqICpvYmo7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCXByX2RlYnVnKCJXaWxsIHdh aXQgZm9yIGRtYS1idWYgd2l0aCBmZCAlZFxuIiwgZmQpOwo+ICsJLyoKPiArCSAqIFRyeSB0byBm aW5kIHRoZSBETUEgYnVmZmVyOiBpZiBub3QgZm91bmQgbWVhbnMgdGhhdAo+ICsJICogZWl0aGVy IHRoZSBidWZmZXIgaGFzIGFscmVhZHkgYmVlbiByZWxlYXNlZCBvciBmaWxlIGRlc2NyaXB0b3IK PiArCSAqIHByb3ZpZGVkIGlzIHdyb25nLgo+ICsJICovCj4gKwl4ZW5fZG1hYnVmID0gZG1hYnVm X2V4cF93YWl0X29ial9nZXRfYnlfZmQocHJpdiwgZmQpOwo+ICsJaWYgKElTX0VSUih4ZW5fZG1h YnVmKSkKPiArCQlyZXR1cm4gUFRSX0VSUih4ZW5fZG1hYnVmKTsKPiArCj4gKwkvKgo+ICsJICog eGVuX2RtYWJ1ZiBzdGlsbCBleGlzdHMgYW5kIGlzIHJlZmVyZW5jZSBjb3VudCBsb2NrZWQgYnkg dXMgbm93LAo+ICsJICogc28gcHJlcGFyZSB0byB3YWl0OiBhbGxvY2F0ZSB3YWl0IG9iamVjdCBh bmQgYWRkIGl0IHRvIHRoZSB3YWl0IGxpc3QsCj4gKwkgKiBzbyB3ZSBjYW4gZmluZCBpdCBvbiBy ZWxlYXNlLgo+ICsJICovCj4gKwlvYmogPSBkbWFidWZfZXhwX3dhaXRfb2JqX25ldyhwcml2LCB4 ZW5fZG1hYnVmKTsKPiArCWlmIChJU19FUlIob2JqKSkgewo+ICsJCXByX2VycigiRmFpbGVkIHRv IHNldHVwIHdhaXQgb2JqZWN0LCByZXQgJWxkXG4iLCBQVFJfRVJSKG9iaikpOwo+ICsJCXJldHVy biBQVFJfRVJSKG9iaik7Cj4gKwl9Cj4gKwo+ICsJcmV0ID0gZG1hYnVmX2V4cF93YWl0X29ial93 YWl0KG9iaiwgd2FpdF90b19tcyk7Cj4gKwlkbWFidWZfZXhwX3dhaXRfb2JqX2ZyZWUocHJpdiwg b2JqKTsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gKy8qIC0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqLwo+ICsvKiBE TUEgYnVmZmVyIGV4cG9ydCBzdXBwb3J0LiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgKi8KPiArLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCj4gKwo+ICtzdGF0aWMgc3RydWN0IHNnX3Rh YmxlICoKPiArZG1hYnVmX3BhZ2VzX3RvX3NndChzdHJ1Y3QgcGFnZSAqKnBhZ2VzLCB1bnNpZ25l ZCBpbnQgbnJfcGFnZXMpCj4gK3sKPiArCXN0cnVjdCBzZ190YWJsZSAqc2d0Owo+ICsJaW50IHJl dDsKPiArCj4gKwlzZ3QgPSBrbWFsbG9jKHNpemVvZigqc2d0KSwgR0ZQX0tFUk5FTCk7Cj4gKwlp ZiAoIXNndCkgewo+ICsJCXJldCA9IC1FTk9NRU07Cj4gKwkJZ290byBvdXQ7Cj4gKwl9Cj4gKwo+ ICsJcmV0ID0gc2dfYWxsb2NfdGFibGVfZnJvbV9wYWdlcyhzZ3QsIHBhZ2VzLCBucl9wYWdlcywg MCwKPiArCQkJCQlucl9wYWdlcyA8PCBQQUdFX1NISUZULAo+ICsJCQkJCUdGUF9LRVJORUwpOwo+ ICsJaWYgKHJldCkKPiArCQlnb3RvIG91dDsKPiArCj4gKwlyZXR1cm4gc2d0Owo+ICsKPiArb3V0 Ogo+ICsJa2ZyZWUoc2d0KTsKPiArCXJldHVybiBFUlJfUFRSKHJldCk7Cj4gK30KPiArCj4gK3N0 YXRpYyBpbnQgZG1hYnVmX2V4cF9vcHNfYXR0YWNoKHN0cnVjdCBkbWFfYnVmICpkbWFfYnVmLAo+ ICsJCQkJIHN0cnVjdCBkZXZpY2UgKnRhcmdldF9kZXYsCj4gKwkJCQkgc3RydWN0IGRtYV9idWZf YXR0YWNobWVudCAqYXR0YWNoKQo+ICt7Cj4gKwlzdHJ1Y3QgeGVuX2RtYWJ1Zl9hdHRhY2htZW50 ICp4ZW5fZG1hYnVmX2F0dGFjaDsKPiArCj4gKwl4ZW5fZG1hYnVmX2F0dGFjaCA9IGt6YWxsb2Mo c2l6ZW9mKCp4ZW5fZG1hYnVmX2F0dGFjaCksIEdGUF9LRVJORUwpOwo+ICsJaWYgKCF4ZW5fZG1h YnVmX2F0dGFjaCkKPiArCQlyZXR1cm4gLUVOT01FTTsKPiArCj4gKwl4ZW5fZG1hYnVmX2F0dGFj aC0+ZGlyID0gRE1BX05PTkU7Cj4gKwlhdHRhY2gtPnByaXYgPSB4ZW5fZG1hYnVmX2F0dGFjaDsK PiArCS8qIE1pZ2h0IG5lZWQgdG8gcGluIHRoZSBwYWdlcyBvZiB0aGUgYnVmZmVyIG5vdy4gKi8K PiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBkbWFidWZfZXhwX29wc19kZXRh Y2goc3RydWN0IGRtYV9idWYgKmRtYV9idWYsCj4gKwkJCQkgIHN0cnVjdCBkbWFfYnVmX2F0dGFj aG1lbnQgKmF0dGFjaCkKPiArewo+ICsJc3RydWN0IHhlbl9kbWFidWZfYXR0YWNobWVudCAqeGVu X2RtYWJ1Zl9hdHRhY2ggPSBhdHRhY2gtPnByaXY7Cj4gKwo+ICsJaWYgKHhlbl9kbWFidWZfYXR0 YWNoKSB7Cj4gKwkJc3RydWN0IHNnX3RhYmxlICpzZ3QgPSB4ZW5fZG1hYnVmX2F0dGFjaC0+c2d0 Owo+ICsKPiArCQlpZiAoc2d0KSB7Cj4gKwkJCWlmICh4ZW5fZG1hYnVmX2F0dGFjaC0+ZGlyICE9 IERNQV9OT05FKQo+ICsJCQkJZG1hX3VubWFwX3NnX2F0dHJzKGF0dGFjaC0+ZGV2LCBzZ3QtPnNn bCwKPiArCQkJCQkJICAgc2d0LT5uZW50cywKPiArCQkJCQkJICAgeGVuX2RtYWJ1Zl9hdHRhY2gt PmRpciwKPiArCQkJCQkJICAgRE1BX0FUVFJfU0tJUF9DUFVfU1lOQyk7Cj4gKwkJCXNnX2ZyZWVf dGFibGUoc2d0KTsKPiArCQl9Cj4gKwo+ICsJCWtmcmVlKHNndCk7Cj4gKwkJa2ZyZWUoeGVuX2Rt YWJ1Zl9hdHRhY2gpOwo+ICsJCWF0dGFjaC0+cHJpdiA9IE5VTEw7Cj4gKwl9Cj4gKwkvKiBNaWdo dCBuZWVkIHRvIHVucGluIHRoZSBwYWdlcyBvZiB0aGUgYnVmZmVyIG5vdy4gKi8KPiArfQo+ICsK PiArc3RhdGljIHN0cnVjdCBzZ190YWJsZSAqCj4gK2RtYWJ1Zl9leHBfb3BzX21hcF9kbWFfYnVm KHN0cnVjdCBkbWFfYnVmX2F0dGFjaG1lbnQgKmF0dGFjaCwKPiArCQkJICAgZW51bSBkbWFfZGF0 YV9kaXJlY3Rpb24gZGlyKQo+ICt7Cj4gKwlzdHJ1Y3QgeGVuX2RtYWJ1Zl9hdHRhY2htZW50ICp4 ZW5fZG1hYnVmX2F0dGFjaCA9IGF0dGFjaC0+cHJpdjsKPiArCXN0cnVjdCB4ZW5fZG1hYnVmICp4 ZW5fZG1hYnVmID0gYXR0YWNoLT5kbWFidWYtPnByaXY7Cj4gKwlzdHJ1Y3Qgc2dfdGFibGUgKnNn dDsKPiArCj4gKwlwcl9kZWJ1ZygiTWFwcGluZyAlZCBwYWdlcyBmb3IgZGV2ICVwXG4iLCB4ZW5f ZG1hYnVmLT5ucl9wYWdlcywKPiArCQkgYXR0YWNoLT5kZXYpOwo+ICsKPiArCWlmIChXQVJOX09O KGRpciA9PSBETUFfTk9ORSB8fCAheGVuX2RtYWJ1Zl9hdHRhY2gpKQo+ICsJCXJldHVybiBFUlJf UFRSKC1FSU5WQUwpOwo+ICsKPiArCS8qIFJldHVybiB0aGUgY2FjaGVkIG1hcHBpbmcgd2hlbiBw b3NzaWJsZS4gKi8KPiArCWlmICh4ZW5fZG1hYnVmX2F0dGFjaC0+ZGlyID09IGRpcikKPiArCQly ZXR1cm4geGVuX2RtYWJ1Zl9hdHRhY2gtPnNndDsKCm1heSBuZWVkIHRvIGNoZWNrIHhlbl9kbWFi dWZfYXR0YWNoLT5zZ3QgPT0gTlVMTCAoaS5lLiBmaXJzdCB0aW1lIG1hcHBpbmcpPwpBbHNvLCBJ IGFtIG5vdCBzdXJlIGlmIHRoaXMgbWVjaGFuaXNtIG9mIHJldXNpbmcgcHJldmlvdXNseSBnZW5l cmF0ZWQgc2d0CmZvciBvdGhlciBtYXBwaW5ncyBpcyB1bml2ZXJzYWxseSBvayBmb3IgYW55IHVz ZS1jYXNlcy4uLiBJIGRvbid0IGtub3cgaWYKaXQgaXMgYWNjZXB0YWJsZSBhcyBwZXIgdGhlIHNw ZWNpZmljYXRpb24uIAoKPiArCj4gKwkvKgo+ICsJICogVHdvIG1hcHBpbmdzIHdpdGggZGlmZmVy ZW50IGRpcmVjdGlvbnMgZm9yIHRoZSBzYW1lIGF0dGFjaG1lbnQgYXJlCj4gKwkgKiBub3QgYWxs b3dlZC4KPiArCSAqLwo+ICsJaWYgKFdBUk5fT04oeGVuX2RtYWJ1Zl9hdHRhY2gtPmRpciAhPSBE TUFfTk9ORSkpCj4gKwkJcmV0dXJuIEVSUl9QVFIoLUVCVVNZKTsKPiArCj4gKwlzZ3QgPSBkbWFi dWZfcGFnZXNfdG9fc2d0KHhlbl9kbWFidWYtPnBhZ2VzLCB4ZW5fZG1hYnVmLT5ucl9wYWdlcyk7 Cj4gKwlpZiAoIUlTX0VSUihzZ3QpKSB7Cj4gKwkJaWYgKCFkbWFfbWFwX3NnX2F0dHJzKGF0dGFj aC0+ZGV2LCBzZ3QtPnNnbCwgc2d0LT5uZW50cywgZGlyLAo+ICsJCQkJICAgICAgRE1BX0FUVFJf U0tJUF9DUFVfU1lOQykpIHsKPiArCQkJc2dfZnJlZV90YWJsZShzZ3QpOwo+ICsJCQlrZnJlZShz Z3QpOwo+ICsJCQlzZ3QgPSBFUlJfUFRSKC1FTk9NRU0pOwo+ICsJCX0gZWxzZSB7Cj4gKwkJCXhl bl9kbWFidWZfYXR0YWNoLT5zZ3QgPSBzZ3Q7Cj4gKwkJCXhlbl9kbWFidWZfYXR0YWNoLT5kaXIg PSBkaXI7Cj4gKwkJfQo+ICsJfQo+ICsJaWYgKElTX0VSUihzZ3QpKQo+ICsJCXByX2VycigiRmFp bGVkIHRvIG1hcCBzZyB0YWJsZSBmb3IgZGV2ICVwXG4iLCBhdHRhY2gtPmRldik7Cj4gKwlyZXR1 cm4gc2d0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBkbWFidWZfZXhwX29wc191bm1hcF9kbWFf YnVmKHN0cnVjdCBkbWFfYnVmX2F0dGFjaG1lbnQgKmF0dGFjaCwKPiArCQkJCQkgc3RydWN0IHNn X3RhYmxlICpzZ3QsCj4gKwkJCQkJIGVudW0gZG1hX2RhdGFfZGlyZWN0aW9uIGRpcikKPiArewo+ ICsJLyogTm90IGltcGxlbWVudGVkLiBUaGUgdW5tYXAgaXMgZG9uZSBhdCBkbWFidWZfZXhwX29w c19kZXRhY2goKS4gKi8KCk5vdCBzdXJlIGlmIGl0J3Mgb2sgdG8gZG8gbm90aGluZyBoZXJlIGJl Y2F1c2UgdGhlIHNwZWMgc2F5cyB0aGlzIGZ1bmN0aW9uIGlzCm1hbmRhdG9yeSBhbmQgaXQgc2hv dWxkIHVubWFwIGFuZCAicmVsZWFzZSIgJnNnX3RhYmxlIGFzc29jaWF0ZWQgd2l0aCBpdC4gCgoJ LyoqCgkgKiBAdW5tYXBfZG1hX2J1ZjoKCSAqCgkgKiBUaGlzIGlzIGNhbGxlZCBieSBkbWFfYnVm X3VubWFwX2F0dGFjaG1lbnQoKSBhbmQgc2hvdWxkIHVubWFwIGFuZAoJICogcmVsZWFzZSB0aGUg JnNnX3RhYmxlIGFsbG9jYXRlZCBpbiBAbWFwX2RtYV9idWYsIGFuZCBpdCBpcyBtYW5kYXRvcnku CgkgKiBJdCBzaG91bGQgYWxzbyB1bnBpbiB0aGUgYmFja2luZyBzdG9yYWdlIGlmIHRoaXMgaXMg dGhlIGxhc3QgbWFwcGluZwoJICogb2YgdGhlIERNQSBidWZmZXIsIGl0IHRoZSBleHBvcnRlciBz dXBwb3J0cyBiYWNraW5nIHN0b3JhZ2UKCSAqIG1pZ3JhdGlvbi4KCSAqLwoKPiArfQo+ICsKPiAr c3RhdGljIHZvaWQgZG1hYnVmX2V4cF9yZWxlYXNlKHN0cnVjdCBrcmVmICprcmVmKQo+ICt7Cj4g KwlzdHJ1Y3QgeGVuX2RtYWJ1ZiAqeGVuX2RtYWJ1ZiA9Cj4gKwkJY29udGFpbmVyX29mKGtyZWYs IHN0cnVjdCB4ZW5fZG1hYnVmLCB1LmV4cC5yZWZjb3VudCk7Cj4gKwo+ICsJZG1hYnVmX2V4cF93 YWl0X29ial9zaWduYWwoeGVuX2RtYWJ1Zi0+cHJpdiwgeGVuX2RtYWJ1Zik7Cj4gKwlsaXN0X2Rl bCgmeGVuX2RtYWJ1Zi0+bmV4dCk7Cj4gKwlrZnJlZSh4ZW5fZG1hYnVmKTsKPiArfQo+ICsKPiAr c3RhdGljIHZvaWQgZG1hYnVmX2V4cF9vcHNfcmVsZWFzZShzdHJ1Y3QgZG1hX2J1ZiAqZG1hX2J1 ZikKPiArewo+ICsJc3RydWN0IHhlbl9kbWFidWYgKnhlbl9kbWFidWYgPSBkbWFfYnVmLT5wcml2 Owo+ICsJc3RydWN0IGdudGRldl9wcml2ICpwcml2ID0geGVuX2RtYWJ1Zi0+cHJpdjsKPiArCj4g KwlnbnRkZXZfcmVtb3ZlX21hcChwcml2LCB4ZW5fZG1hYnVmLT51LmV4cC5tYXApOwo+ICsJbXV0 ZXhfbG9jaygmcHJpdi0+ZG1hYnVmX2xvY2spOwo+ICsJa3JlZl9wdXQoJnhlbl9kbWFidWYtPnUu ZXhwLnJlZmNvdW50LCBkbWFidWZfZXhwX3JlbGVhc2UpOwo+ICsJbXV0ZXhfdW5sb2NrKCZwcml2 LT5kbWFidWZfbG9jayk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkICpkbWFidWZfZXhwX29wc19r bWFwX2F0b21pYyhzdHJ1Y3QgZG1hX2J1ZiAqZG1hX2J1ZiwKPiArCQkJCQl1bnNpZ25lZCBsb25n IHBhZ2VfbnVtKQo+ICt7Cj4gKwkvKiBOb3QgaW1wbGVtZW50ZWQuICovCj4gKwlyZXR1cm4gTlVM TDsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgZG1hYnVmX2V4cF9vcHNfa3VubWFwX2F0b21pYyhz dHJ1Y3QgZG1hX2J1ZiAqZG1hX2J1ZiwKPiArCQkJCQkgdW5zaWduZWQgbG9uZyBwYWdlX251bSwg dm9pZCAqYWRkcikKPiArewo+ICsJLyogTm90IGltcGxlbWVudGVkLiAqLwo+ICt9Cj4gKwo+ICtz dGF0aWMgdm9pZCAqZG1hYnVmX2V4cF9vcHNfa21hcChzdHJ1Y3QgZG1hX2J1ZiAqZG1hX2J1ZiwK PiArCQkJCSB1bnNpZ25lZCBsb25nIHBhZ2VfbnVtKQo+ICt7Cj4gKwkvKiBOb3QgaW1wbGVtZW50 ZWQuICovCj4gKwlyZXR1cm4gTlVMTDsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgZG1hYnVmX2V4 cF9vcHNfa3VubWFwKHN0cnVjdCBkbWFfYnVmICpkbWFfYnVmLAo+ICsJCQkJICB1bnNpZ25lZCBs b25nIHBhZ2VfbnVtLCB2b2lkICphZGRyKQo+ICt7Cj4gKwkvKiBOb3QgaW1wbGVtZW50ZWQuICov Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgZG1hYnVmX2V4cF9vcHNfbW1hcChzdHJ1Y3QgZG1hX2J1 ZiAqZG1hX2J1ZiwKPiArCQkJICAgICAgIHN0cnVjdCB2bV9hcmVhX3N0cnVjdCAqdm1hKQo+ICt7 Cj4gKwkvKiBOb3QgaW1wbGVtZW50ZWQuICovCj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiArc3Rh dGljIGNvbnN0IHN0cnVjdCBkbWFfYnVmX29wcyBkbWFidWZfZXhwX29wcyA9ICB7Cj4gKwkuYXR0 YWNoID0gZG1hYnVmX2V4cF9vcHNfYXR0YWNoLAo+ICsJLmRldGFjaCA9IGRtYWJ1Zl9leHBfb3Bz X2RldGFjaCwKPiArCS5tYXBfZG1hX2J1ZiA9IGRtYWJ1Zl9leHBfb3BzX21hcF9kbWFfYnVmLAo+ ICsJLnVubWFwX2RtYV9idWYgPSBkbWFidWZfZXhwX29wc191bm1hcF9kbWFfYnVmLAo+ICsJLnJl bGVhc2UgPSBkbWFidWZfZXhwX29wc19yZWxlYXNlLAo+ICsJLm1hcCA9IGRtYWJ1Zl9leHBfb3Bz X2ttYXAsCj4gKwkubWFwX2F0b21pYyA9IGRtYWJ1Zl9leHBfb3BzX2ttYXBfYXRvbWljLAo+ICsJ LnVubWFwID0gZG1hYnVmX2V4cF9vcHNfa3VubWFwLAo+ICsJLnVubWFwX2F0b21pYyA9IGRtYWJ1 Zl9leHBfb3BzX2t1bm1hcF9hdG9taWMsCj4gKwkubW1hcCA9IGRtYWJ1Zl9leHBfb3BzX21tYXAs Cj4gK307Cj4gKwo+ICtzdGF0aWMgaW50IGRtYWJ1Zl9leHBvcnQoc3RydWN0IGdudGRldl9wcml2 ICpwcml2LCBzdHJ1Y3QgZ3JhbnRfbWFwICptYXAsCj4gKwkJCSBpbnQgKmZkKQo+ICt7Cj4gKwlE RUZJTkVfRE1BX0JVRl9FWFBPUlRfSU5GTyhleHBfaW5mbyk7Cj4gKwlzdHJ1Y3QgeGVuX2RtYWJ1 ZiAqeGVuX2RtYWJ1ZjsKPiArCWludCByZXQgPSAwOwo+ICsKPiArCXhlbl9kbWFidWYgPSBremFs bG9jKHNpemVvZigqeGVuX2RtYWJ1ZiksIEdGUF9LRVJORUwpOwo+ICsJaWYgKCF4ZW5fZG1hYnVm KQo+ICsJCXJldHVybiAtRU5PTUVNOwo+ICsKPiArCWtyZWZfaW5pdCgmeGVuX2RtYWJ1Zi0+dS5l eHAucmVmY291bnQpOwo+ICsKPiArCXhlbl9kbWFidWYtPnByaXYgPSBwcml2Owo+ICsJeGVuX2Rt YWJ1Zi0+bnJfcGFnZXMgPSBtYXAtPmNvdW50Owo+ICsJeGVuX2RtYWJ1Zi0+cGFnZXMgPSBtYXAt PnBhZ2VzOwo+ICsJeGVuX2RtYWJ1Zi0+dS5leHAubWFwID0gbWFwOwo+ICsKPiArCWV4cF9pbmZv LmV4cF9uYW1lID0gS0JVSUxEX01PRE5BTUU7Cj4gKwlpZiAobWFwLT5kbWFfZGV2LT5kcml2ZXIg JiYgbWFwLT5kbWFfZGV2LT5kcml2ZXItPm93bmVyKQo+ICsJCWV4cF9pbmZvLm93bmVyID0gbWFw LT5kbWFfZGV2LT5kcml2ZXItPm93bmVyOwo+ICsJZWxzZQo+ICsJCWV4cF9pbmZvLm93bmVyID0g VEhJU19NT0RVTEU7Cj4gKwlleHBfaW5mby5vcHMgPSAmZG1hYnVmX2V4cF9vcHM7Cj4gKwlleHBf aW5mby5zaXplID0gbWFwLT5jb3VudCA8PCBQQUdFX1NISUZUOwo+ICsJZXhwX2luZm8uZmxhZ3Mg PSBPX1JEV1I7Cj4gKwlleHBfaW5mby5wcml2ID0geGVuX2RtYWJ1ZjsKPiArCj4gKwl4ZW5fZG1h YnVmLT5kbWFidWYgPSBkbWFfYnVmX2V4cG9ydCgmZXhwX2luZm8pOwo+ICsJaWYgKElTX0VSUih4 ZW5fZG1hYnVmLT5kbWFidWYpKSB7Cj4gKwkJcmV0ID0gUFRSX0VSUih4ZW5fZG1hYnVmLT5kbWFi dWYpOwo+ICsJCXhlbl9kbWFidWYtPmRtYWJ1ZiA9IE5VTEw7Cj4gKwkJZ290byBmYWlsOwo+ICsJ fQo+ICsKPiArCXJldCA9IGRtYV9idWZfZmQoeGVuX2RtYWJ1Zi0+ZG1hYnVmLCBPX0NMT0VYRUMp Owo+ICsJaWYgKHJldCA8IDApCj4gKwkJZ290byBmYWlsOwo+ICsKPiArCXhlbl9kbWFidWYtPmZk ID0gcmV0Owo+ICsJKmZkID0gcmV0Owo+ICsKPiArCXByX2RlYnVnKCJFeHBvcnRpbmcgRE1BIGJ1 ZmZlciB3aXRoIGZkICVkXG4iLCByZXQpOwo+ICsKPiArCW11dGV4X2xvY2soJnByaXYtPmRtYWJ1 Zl9sb2NrKTsKPiArCWxpc3RfYWRkKCZ4ZW5fZG1hYnVmLT5uZXh0LCAmcHJpdi0+ZG1hYnVmX2V4 cF9saXN0KTsKPiArCW11dGV4X3VubG9jaygmcHJpdi0+ZG1hYnVmX2xvY2spOwo+ICsJcmV0dXJu IDA7Cj4gKwo+ICtmYWlsOgo+ICsJaWYgKHhlbl9kbWFidWYtPmRtYWJ1ZikKPiArCQlkbWFfYnVm X3B1dCh4ZW5fZG1hYnVmLT5kbWFidWYpOwo+ICsJa2ZyZWUoeGVuX2RtYWJ1Zik7Cj4gKwlyZXR1 cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgc3RydWN0IGdyYW50X21hcCAqCj4gK2RtYWJ1Zl9l eHBfYWxsb2NfYmFja2luZ19zdG9yYWdlKHN0cnVjdCBnbnRkZXZfcHJpdiAqcHJpdiwgaW50IGRt YWJ1Zl9mbGFncywKPiArCQkJCSBpbnQgY291bnQpCj4gK3sKPiArCXN0cnVjdCBncmFudF9tYXAg Km1hcDsKPiArCj4gKwlpZiAodW5saWtlbHkoY291bnQgPD0gMCkpCj4gKwkJcmV0dXJuIEVSUl9Q VFIoLUVJTlZBTCk7Cj4gKwo+ICsJaWYgKChkbWFidWZfZmxhZ3MgJiBHTlRERVZfRE1BX0ZMQUdf V0MpICYmCj4gKwkgICAgKGRtYWJ1Zl9mbGFncyAmIEdOVERFVl9ETUFfRkxBR19DT0hFUkVOVCkp IHsKPiArCQlwcl9lcnIoIldyb25nIGRtYS1idWYgZmxhZ3M6IGVpdGhlciBXQyBvciBjb2hlcmVu dCwgbm90IGJvdGhcbiIpOwo+ICsJCXJldHVybiBFUlJfUFRSKC1FSU5WQUwpOwo+ICsJfQo+ICsK PiArCW1hcCA9IGdudGRldl9hbGxvY19tYXAocHJpdiwgY291bnQsIGRtYWJ1Zl9mbGFncyk7Cj4g KwlpZiAoIW1hcCkKPiArCQlyZXR1cm4gRVJSX1BUUigtRU5PTUVNKTsKPiArCj4gKwlpZiAodW5s aWtlbHkoYXRvbWljX2FkZF9yZXR1cm4oY291bnQsICZwYWdlc19tYXBwZWQpID4gbGltaXQpKSB7 Cj4gKwkJcHJfZXJyKCJjYW4ndCBtYXA6IG92ZXIgbGltaXRcbiIpOwo+ICsJCWdudGRldl9wdXRf bWFwKE5VTEwsIG1hcCk7Cj4gKwkJcmV0dXJuIEVSUl9QVFIoLUVOT01FTSk7Cj4gKwl9Cj4gKwly ZXR1cm4gbWFwOwo+ICB9CgpXaGVuIGFuZCBob3cgd291bGQgdGhpcyBhbGxvY2F0aW9uIGJlIGZy ZWVkPyBJIGRvbid0IHNlZSBhbnkgaW9jdGwgZm9yIGZyZWVpbmcgdXAKc2hhcmVkIHBhZ2VzLgoK PiAgCj4gIHN0YXRpYyBpbnQgZG1hYnVmX2V4cF9mcm9tX3JlZnMoc3RydWN0IGdudGRldl9wcml2 ICpwcml2LCBpbnQgZmxhZ3MsCj4gIAkJCQlpbnQgY291bnQsIHUzMiBkb21pZCwgdTMyICpyZWZz LCB1MzIgKmZkKQo+ICB7Cj4gKwlzdHJ1Y3QgZ3JhbnRfbWFwICptYXA7Cj4gKwlpbnQgaSwgcmV0 Owo+ICsKPiAgCSpmZCA9IC0xOwo+IC0JcmV0dXJuIC1FSU5WQUw7Cj4gKwo+ICsJaWYgKHVzZV9w dGVtb2QpIHsKPiArCQlwcl9lcnIoIkNhbm5vdCBwcm92aWRlIGRtYS1idWY6IHVzZV9wdGVtb2Rl ICVkXG4iLAo+ICsJCSAgICAgICB1c2VfcHRlbW9kKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiAr CX0KPiArCj4gKwltYXAgPSBkbWFidWZfZXhwX2FsbG9jX2JhY2tpbmdfc3RvcmFnZShwcml2LCBm bGFncywgY291bnQpOwo+ICsJaWYgKElTX0VSUihtYXApKQo+ICsJCXJldHVybiBQVFJfRVJSKG1h cCk7Cj4gKwo+ICsJZm9yIChpID0gMDsgaSA8IGNvdW50OyBpKyspIHsKPiArCQltYXAtPmdyYW50 c1tpXS5kb21pZCA9IGRvbWlkOwo+ICsJCW1hcC0+Z3JhbnRzW2ldLnJlZiA9IHJlZnNbaV07Cj4g Kwl9Cj4gKwo+ICsJbXV0ZXhfbG9jaygmcHJpdi0+bG9jayk7Cj4gKwlnbnRkZXZfYWRkX21hcChw cml2LCBtYXApOwo+ICsJbXV0ZXhfdW5sb2NrKCZwcml2LT5sb2NrKTsKPiArCj4gKwltYXAtPmZs YWdzIHw9IEdOVE1BUF9ob3N0X21hcDsKPiArI2lmIGRlZmluZWQoQ09ORklHX1g4NikKPiArCW1h cC0+ZmxhZ3MgfD0gR05UTUFQX2RldmljZV9tYXA7Cj4gKyNlbmRpZgo+ICsKPiArCXJldCA9IG1h cF9ncmFudF9wYWdlcyhtYXApOwo+ICsJaWYgKHJldCA8IDApCj4gKwkJZ290byBvdXQ7Cj4gKwo+ ICsJcmV0ID0gZG1hYnVmX2V4cG9ydChwcml2LCBtYXAsIGZkKTsKPiArCWlmIChyZXQgPCAwKQo+ ICsJCWdvdG8gb3V0Owo+ICsKPiArCXJldHVybiAwOwo+ICsKPiArb3V0Ogo+ICsJZ250ZGV2X3Jl bW92ZV9tYXAocHJpdiwgbWFwKTsKPiArCXJldHVybiByZXQ7Cj4gIH0KPiAgCj4gIC8qIC0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLSAqLwo+IC0tIAo+IDIuMTcuMAo+IApfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fXwpkcmktZGV2ZWwgbWFpbGluZyBsaXN0CmRyaS1kZXZlbEBsaXN0cy5m cmVlZGVza3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0 aW5mby9kcmktZGV2ZWwK