From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 63951C2B9F8 for ; Tue, 25 May 2021 10:08:03 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (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 1B7F861408 for ; Tue, 25 May 2021 10:08:03 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1B7F861408 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 232BE6E9E3; Tue, 25 May 2021 10:08:02 +0000 (UTC) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by gabe.freedesktop.org (Postfix) with ESMTPS id CCAF66E9E3; Tue, 25 May 2021 10:08:00 +0000 (UTC) IronPort-SDR: D3OkIHi+CsJmWb3jftFVSVEQzdS6M/y0jaJM1Zae68ef6WdnTcJztv/TQ91vkd6A5TJhXEsnog ywXbAtrFKKCA== X-IronPort-AV: E=McAfee;i="6200,9189,9994"; a="266050123" X-IronPort-AV: E=Sophos;i="5.82,328,1613462400"; d="scan'208";a="266050123" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 May 2021 03:07:59 -0700 IronPort-SDR: FdzQSl8KiSA6Av1UDf0hMpmPETx8ii8XjM7SpbUTM9+ch8mW5vs7EIdfaBWkfcdPzZQNASn3sv LRu53tddM4kw== X-IronPort-AV: E=Sophos;i="5.82,328,1613462400"; d="scan'208";a="630170655" Received: from vkubarev-mobl1.ccr.corp.intel.com ([10.249.254.43]) by fmsmga006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 May 2021 03:07:58 -0700 Message-ID: Subject: Re: [Intel-gfx] [PATCH v3 06/12] drm/ttm: Add a generic TTM memcpy move for page-based iomem From: Thomas =?ISO-8859-1?Q?Hellstr=F6m?= To: Matthew Auld Date: Tue, 25 May 2021 12:07:55 +0200 In-Reply-To: References: <20210521153253.518037-1-thomas.hellstrom@linux.intel.com> <20210521153253.518037-7-thomas.hellstrom@linux.intel.com> <2cc9a60c-4360-40b6-8712-1e50b7bbfd03@linux.intel.com> Content-Type: text/plain; charset="UTF-8" User-Agent: Evolution 3.38.4 (3.38.4-1.fc33) MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Intel Graphics Development , Christian =?ISO-8859-1?Q?K=F6nig?= , ML dri-devel Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" On Tue, 2021-05-25 at 10:58 +0100, Matthew Auld wrote: > On Tue, 25 May 2021 at 10:32, Thomas Hellström > wrote: > > > > > > On 5/25/21 11:18 AM, Matthew Auld wrote: > > > On Fri, 21 May 2021 at 16:33, Thomas Hellström > > > wrote: > > > > The internal ttm_bo_util memcpy uses ioremap functionality, and > > > > while it > > > > probably might be possible to use it for copying in- and out of > > > > sglist represented io memory, using io_mem_reserve() / > > > > io_mem_free() > > > > callbacks, that would cause problems with fault(). > > > > Instead, implement a method mapping page-by-page using > > > > kmap_local() > > > > semantics. As an additional benefit we then avoid the > > > > occasional global > > > > TLB flushes of ioremap() and consuming ioremap space, > > > > elimination of a > > > > critical point of failure and with a slight change of semantics > > > > we could > > > > also push the memcpy out async for testing and async driver > > > > development > > > > purposes. > > > > > > > > A special linear iomem iterator is introduced internally to > > > > mimic the > > > > old ioremap behaviour for code-paths that can't immediately be > > > > ported > > > > over. This adds to the code size and should be considered a > > > > temporary > > > > solution. > > > > > > > > Looking at the code we have a lot of checks for iomap tagged > > > > pointers. > > > > Ideally we should extend the core memremap functions to also > > > > accept > > > > uncached memory and kmap_local functionality. Then we could > > > > strip a > > > > lot of code. > > > > > > > > Cc: Christian König > > > > Signed-off-by: Thomas Hellström < > > > > thomas.hellstrom@linux.intel.com> > > > > --- > > > > v3: > > > > - Split up in various TTM files and addressed review comments > > > > by > > > >    Christian König. Tested and fixed legacy iomap memcpy path > > > > on i915. > > > > --- > > > >   drivers/gpu/drm/ttm/ttm_bo_util.c  | 278 ++++++++++---------- > > > > --------- > > > >   drivers/gpu/drm/ttm/ttm_module.c   |  35 ++++ > > > >   drivers/gpu/drm/ttm/ttm_resource.c | 166 +++++++++++++++++ > > > >   drivers/gpu/drm/ttm/ttm_tt.c       |  42 +++++ > > > >   include/drm/ttm/ttm_bo_driver.h    |  28 +++ > > > >   include/drm/ttm/ttm_caching.h      |   2 + > > > >   include/drm/ttm/ttm_kmap_iter.h    |  61 +++++++ > > > >   include/drm/ttm/ttm_resource.h     |  61 +++++++ > > > >   include/drm/ttm/ttm_tt.h           |  16 ++ > > > >   9 files changed, 508 insertions(+), 181 deletions(-) > > > >   create mode 100644 include/drm/ttm/ttm_kmap_iter.h > > > > > > > > diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c > > > > b/drivers/gpu/drm/ttm/ttm_bo_util.c > > > > index ae8b61460724..912cbe8e60a2 100644 > > > > --- a/drivers/gpu/drm/ttm/ttm_bo_util.c > > > > +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c > > > > @@ -72,190 +72,126 @@ void ttm_mem_io_free(struct ttm_device > > > > *bdev, > > > >          mem->bus.addr = NULL; > > > >   } > > > > > > > > -static int ttm_resource_ioremap(struct ttm_device *bdev, > > > > -                              struct ttm_resource *mem, > > > > -                              void **virtual) > > > > +/** > > > > + * ttm_move_memcpy - Helper to perform a memcpy ttm move > > > > operation. > > > > + * @bo: The struct ttm_buffer_object. > > > > + * @new_mem: The struct ttm_resource we're moving to (copy > > > > destination). > > > > + * @new_iter: A struct ttm_kmap_iter representing the > > > > destination resource. > > > > + * @src_iter: A struct ttm_kmap_iter representing the source > > > > resource. > > > > + * > > > > + * This function is intended to be able to move out async > > > > under a > > > > + * dma-fence if desired. > > > > + */ > > > > +void ttm_move_memcpy(struct ttm_buffer_object *bo, > > > > +                    struct ttm_resource *dst_mem, > > > > +                    struct ttm_kmap_iter *dst_iter, > > > > +                    struct ttm_kmap_iter *src_iter) > > > >   { > > > > -       int ret; > > > > -       void *addr; > > > > - > > > > -       *virtual = NULL; > > > > -       ret = ttm_mem_io_reserve(bdev, mem); > > > > -       if (ret || !mem->bus.is_iomem) > > > > -               return ret; > > > > +       const struct ttm_kmap_iter_ops *dst_ops = dst_iter- > > > > >ops; > > > > +       const struct ttm_kmap_iter_ops *src_ops = src_iter- > > > > >ops; > > > > +       struct ttm_tt *ttm = bo->ttm; > > > > +       struct dma_buf_map src_map, dst_map; > > > > +       pgoff_t i; > > > > > > > > -       if (mem->bus.addr) { > > > > -               addr = mem->bus.addr; > > > > -       } else { > > > > -               size_t bus_size = (size_t)mem->num_pages << > > > > PAGE_SHIFT; > > > > +       /* Single TTM move. NOP */ > > > > +       if (dst_ops->maps_tt && src_ops->maps_tt) > > > > +               return; > > > > > > > > -               if (mem->bus.caching == ttm_write_combined) > > > > -                       addr = ioremap_wc(mem->bus.offset, > > > > bus_size); > > > > -#ifdef CONFIG_X86 > > > > -               else if (mem->bus.caching == ttm_cached) > > > > -                       addr = ioremap_cache(mem->bus.offset, > > > > bus_size); > > > > -#endif > > > > -               else > > > > -                       addr = ioremap(mem->bus.offset, > > > > bus_size); > > > > -               if (!addr) { > > > > -                       ttm_mem_io_free(bdev, mem); > > > > -                       return -ENOMEM; > > > > +       /* Don't move nonexistent data. Clear destination > > > > instead. */ > > > > +       if (src_ops->maps_tt && (!ttm || > > > > !ttm_tt_is_populated(ttm))) { > > > > +               if (ttm && !(ttm->page_flags & > > > > TTM_PAGE_FLAG_ZERO_ALLOC)) > > > > +                       return; > > > > + > > > > +               for (i = 0; i < dst_mem->num_pages; ++i) { > > > > +                       dst_ops->map_local(dst_iter, &dst_map, > > > > i); > > > > +                       if (dst_map.is_iomem) > > > > +                               memset_io(dst_map.vaddr_iomem, > > > > 0, PAGE_SIZE); > > > > +                       else > > > > +                               memset(dst_map.vaddr, 0, > > > > PAGE_SIZE); > > > > +                       if (dst_ops->unmap_local) > > > > +                               dst_ops->unmap_local(dst_iter, > > > > &dst_map); > > > >                  } > > > > +               return; > > > >          } > > > > -       *virtual = addr; > > > > -       return 0; > > > > -} > > > > - > > > > -static void ttm_resource_iounmap(struct ttm_device *bdev, > > > > -                               struct ttm_resource *mem, > > > > -                               void *virtual) > > > > -{ > > > > -       if (virtual && mem->bus.addr == NULL) > > > > -               iounmap(virtual); > > > > -       ttm_mem_io_free(bdev, mem); > > > > -} > > > > - > > > > -static int ttm_copy_io_page(void *dst, void *src, unsigned > > > > long page) > > > > -{ > > > > -       uint32_t *dstP = > > > > -           (uint32_t *) ((unsigned long)dst + (page << > > > > PAGE_SHIFT)); > > > > -       uint32_t *srcP = > > > > -           (uint32_t *) ((unsigned long)src + (page << > > > > PAGE_SHIFT)); > > > > - > > > > -       int i; > > > > -       for (i = 0; i < PAGE_SIZE / sizeof(uint32_t); ++i) > > > > -               iowrite32(ioread32(srcP++), dstP++); > > > > -       return 0; > > > > -} > > > > - > > > > -static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src, > > > > -                               unsigned long page, > > > > -                               pgprot_t prot) > > > > -{ > > > > -       struct page *d = ttm->pages[page]; > > > > -       void *dst; > > > > - > > > > -       if (!d) > > > > -               return -ENOMEM; > > > > - > > > > -       src = (void *)((unsigned long)src + (page << > > > > PAGE_SHIFT)); > > > > -       dst = kmap_atomic_prot(d, prot); > > > > -       if (!dst) > > > > -               return -ENOMEM; > > > > - > > > > -       memcpy_fromio(dst, src, PAGE_SIZE); > > > > - > > > > -       kunmap_atomic(dst); > > > > - > > > > -       return 0; > > > > -} > > > > - > > > > -static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst, > > > > -                               unsigned long page, > > > > -                               pgprot_t prot) > > > > -{ > > > > -       struct page *s = ttm->pages[page]; > > > > -       void *src; > > > > - > > > > -       if (!s) > > > > -               return -ENOMEM; > > > > - > > > > -       dst = (void *)((unsigned long)dst + (page << > > > > PAGE_SHIFT)); > > > > -       src = kmap_atomic_prot(s, prot); > > > > -       if (!src) > > > > -               return -ENOMEM; > > > > > > > > -       memcpy_toio(dst, src, PAGE_SIZE); > > > > - > > > > -       kunmap_atomic(src); > > > > +       for (i = 0; i < dst_mem->num_pages; ++i) { > > > > +               dst_ops->map_local(dst_iter, &dst_map, i); > > > > +               src_ops->map_local(src_iter, &src_map, i); > > > > + > > > > +               if (!src_map.is_iomem && !dst_map.is_iomem) { > > > > +                       memcpy(dst_map.vaddr, src_map.vaddr, > > > > PAGE_SIZE); > > > > +               } else if (!src_map.is_iomem) { > > > > +                       dma_buf_map_memcpy_to(&dst_map, > > > > src_map.vaddr, > > > > +                                             PAGE_SIZE); > > > > +               } else if (!dst_map.is_iomem) { > > > > +                       memcpy_fromio(dst_map.vaddr, > > > > src_map.vaddr_iomem, > > > > +                                     PAGE_SIZE); > > > > +               } else { > > > > +                       int j; > > > > +                       u32 __iomem *src = src_map.vaddr_iomem; > > > > +                       u32 __iomem *dst = dst_map.vaddr_iomem; > > > > > > > > -       return 0; > > > > +                       for (j = 0; j < (PAGE_SIZE >> 2); ++j) > > > IMO PAGE_SIZE / sizeof(u32) is easier to understand. > > > > OK, will fix. > > > > > > > > > > > +                               iowrite32(ioread32(src++), > > > > dst++); > > > > +               } > > > > +               if (src_ops->unmap_local) > > > > +                       src_ops->unmap_local(src_iter, > > > > &src_map); > > > > +               if (dst_ops->unmap_local) > > > > +                       dst_ops->unmap_local(dst_iter, > > > > &dst_map); > > > > +       } > > > >   } > > > > +EXPORT_SYMBOL(ttm_move_memcpy); > > > > > > > >   int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, > > > >                         struct ttm_operation_ctx *ctx, > > > > -                      struct ttm_resource *new_mem) > > > > +                      struct ttm_resource *dst_mem) > > > >   { > > > >          struct ttm_device *bdev = bo->bdev; > > > > -       struct ttm_resource_manager *man = > > > > ttm_manager_type(bdev, new_mem->mem_type); > > > > +       struct ttm_resource_manager *dst_man = > > > > +               ttm_manager_type(bo->bdev, dst_mem->mem_type); > > > >          struct ttm_tt *ttm = bo->ttm; > > > > -       struct ttm_resource *old_mem = &bo->mem; > > > > -       struct ttm_resource old_copy = *old_mem; > > > > -       void *old_iomap; > > > > -       void *new_iomap; > > > > +       struct ttm_resource *src_mem = &bo->mem; > > > > +       struct ttm_resource_manager *src_man = > > > > +               ttm_manager_type(bdev, src_mem->mem_type); > > > > +       struct ttm_resource src_copy = *src_mem; > > > > +       union { > > > > +               struct ttm_kmap_iter_tt tt; > > > > +               struct ttm_kmap_iter_linear_io io; > > > > +       } _dst_iter, _src_iter; > > > > +       struct ttm_kmap_iter *dst_iter, *src_iter; > > > >          int ret; > > > > -       unsigned long i; > > > > > > > > -       ret = ttm_bo_wait_ctx(bo, ctx); > > > > -       if (ret) > > > > -               return ret; > > > > - > > > > -       ret = ttm_resource_ioremap(bdev, old_mem, &old_iomap); > > > > -       if (ret) > > > > -               return ret; > > > > -       ret = ttm_resource_ioremap(bdev, new_mem, &new_iomap); > > > > -       if (ret) > > > > -               goto out; > > > > - > > > > -       /* > > > > -        * Single TTM move. NOP. > > > > -        */ > > > > -       if (old_iomap == NULL && new_iomap == NULL) > > > > -               goto out2; > > > > - > > > > -       /* > > > > -        * Don't move nonexistent data. Clear destination > > > > instead. > > > > -        */ > > > > -       if (old_iomap == NULL && > > > > -           (ttm == NULL || (!ttm_tt_is_populated(ttm) && > > > > -                            !(ttm->page_flags & > > > > TTM_PAGE_FLAG_SWAPPED)))) { > > > > -               memset_io(new_iomap, 0, new_mem- > > > > >num_pages*PAGE_SIZE); > > > > -               goto out2; > > > > -       } > > > > - > > > > -       /* > > > > -        * TTM might be null for moves within the same region. > > > > -        */ > > > > -       if (ttm) { > > > > +       if (ttm && ((ttm->page_flags & TTM_PAGE_FLAG_SWAPPED) > > > > || > > > > +                   dst_man->use_tt)) { > > > >                  ret = ttm_tt_populate(bdev, ttm, ctx); > > > >                  if (ret) > > > > -                       goto out1; > > > > +                       return ret; > > > >          } > > > > > > > > -       for (i = 0; i < new_mem->num_pages; ++i) { > > > > -               if (old_iomap == NULL) { > > > > -                       pgprot_t prot = ttm_io_prot(bo, > > > > old_mem, PAGE_KERNEL); > > > > -                       ret = ttm_copy_ttm_io_page(ttm, > > > > new_iomap, i, > > > > -                                                  prot); > > > > -               } else if (new_iomap == NULL) { > > > > -                       pgprot_t prot = ttm_io_prot(bo, > > > > new_mem, PAGE_KERNEL); > > > > -                       ret = ttm_copy_io_ttm_page(ttm, > > > > old_iomap, i, > > > > -                                                  prot); > > > > -               } else { > > > > -                       ret = ttm_copy_io_page(new_iomap, > > > > old_iomap, i); > > > > -               } > > > > -               if (ret) > > > > -                       goto out1; > > > > +       dst_iter = ttm_kmap_iter_linear_io_init(&_dst_iter.io, > > > > bdev, dst_mem); > > > > +       if (PTR_ERR(dst_iter) == -EINVAL && dst_man->use_tt) > > > > +               dst_iter = ttm_kmap_iter_tt_init(&_dst_iter.tt, > > > > bo->ttm); > > > > +       if (IS_ERR(dst_iter)) > > > > +               return PTR_ERR(dst_iter); > > > > + > > > > +       src_iter = ttm_kmap_iter_linear_io_init(&_src_iter.io, > > > > bdev, src_mem); > > > > +       if (PTR_ERR(src_iter) == -EINVAL && src_man->use_tt) > > > > +               src_iter = ttm_kmap_iter_tt_init(&_src_iter.tt, > > > > bo->ttm); > > > > +       if (IS_ERR(src_iter)) { > > > > +               ret = PTR_ERR(src_iter); > > > > +               goto out_src_iter; > > > >          } > > > > -       mb(); > > > > -out2: > > > > -       old_copy = *old_mem; > > > > > > > > -       ttm_bo_assign_mem(bo, new_mem); > > > > - > > > > -       if (!man->use_tt) > > > > -               ttm_bo_tt_destroy(bo); > > > > +       ttm_move_memcpy(bo, dst_mem, dst_iter, src_iter); > > > > +       src_copy = *src_mem; > > > > +       ttm_bo_move_sync_cleanup(bo, dst_mem); > > > > > > > > -out1: > > > > -       ttm_resource_iounmap(bdev, old_mem, new_iomap); > > > > -out: > > > > -       ttm_resource_iounmap(bdev, &old_copy, old_iomap); > > > > +       if (!src_iter->ops->maps_tt) > > > > +               ttm_kmap_iter_linear_io_fini(&_src_iter.io, > > > > bdev, &src_copy); > > > > +out_src_iter: > > > > +       if (!dst_iter->ops->maps_tt) > > > > +               ttm_kmap_iter_linear_io_fini(&_dst_iter.io, > > > > bdev, dst_mem); > > > > > > > > -       /* > > > > -        * On error, keep the mm node! > > > > -        */ > > > > -       if (!ret) > > > > -               ttm_resource_free(bo, &old_copy); > > > >          return ret; > > > >   } > > > >   EXPORT_SYMBOL(ttm_bo_move_memcpy); > > > > @@ -336,27 +272,7 @@ pgprot_t ttm_io_prot(struct > > > > ttm_buffer_object *bo, struct ttm_resource *res, > > > >          man = ttm_manager_type(bo->bdev, res->mem_type); > > > >          caching = man->use_tt ? bo->ttm->caching : res- > > > > >bus.caching; > > > > > > > > -       /* Cached mappings need no adjustment */ > > > > -       if (caching == ttm_cached) > > > > -               return tmp; > > > > - > > > > -#if defined(__i386__) || defined(__x86_64__) > > > > -       if (caching == ttm_write_combined) > > > > -               tmp = pgprot_writecombine(tmp); > > > > -       else if (boot_cpu_data.x86 > 3) > > > > -               tmp = pgprot_noncached(tmp); > > > > -#endif > > > > -#if defined(__ia64__) || defined(__arm__) || > > > > defined(__aarch64__) || \ > > > > -    defined(__powerpc__) || defined(__mips__) > > > > -       if (caching == ttm_write_combined) > > > > -               tmp = pgprot_writecombine(tmp); > > > > -       else > > > > -               tmp = pgprot_noncached(tmp); > > > > -#endif > > > > -#if defined(__sparc__) > > > > -       tmp = pgprot_noncached(tmp); > > > > -#endif > > > > -       return tmp; > > > > +       return ttm_prot_from_caching(caching, tmp); > > > >   } > > > >   EXPORT_SYMBOL(ttm_io_prot); > > > > > > > > diff --git a/drivers/gpu/drm/ttm/ttm_module.c > > > > b/drivers/gpu/drm/ttm/ttm_module.c > > > > index 56b0efdba1a9..997c458f68a9 100644 > > > > --- a/drivers/gpu/drm/ttm/ttm_module.c > > > > +++ b/drivers/gpu/drm/ttm/ttm_module.c > > > > @@ -31,12 +31,47 @@ > > > >    */ > > > >   #include > > > >   #include > > > > +#include > > > >   #include > > > >   #include > > > >   #include > > > > +#include > > > > > > > >   #include "ttm_module.h" > > > > > > > > +/** > > > > + * ttm_prot_from_caching - Modify the page protection > > > > according to the > > > > + * ttm cacing mode > > > > + * @caching: The ttm caching mode > > > > + * @tmp: The original page protection > > > > + * > > > > + * Return: The modified page protection > > > > + */ > > > > +pgprot_t ttm_prot_from_caching(enum ttm_caching caching, > > > > pgprot_t tmp) > > > > +{ > > > > +       /* Cached mappings need no adjustment */ > > > > +       if (caching == ttm_cached) > > > > +               return tmp; > > > > + > > > > +#if defined(__i386__) || defined(__x86_64__) > > > > +       if (caching == ttm_write_combined) > > > > +               tmp = pgprot_writecombine(tmp); > > > > +       else if (boot_cpu_data.x86 > 3) > > > > +               tmp = pgprot_noncached(tmp); > > > > +#endif > > > > +#if defined(__ia64__) || defined(__arm__) || > > > > defined(__aarch64__) || \ > > > > +       defined(__powerpc__) || defined(__mips__) > > > > +       if (caching == ttm_write_combined) > > > > +               tmp = pgprot_writecombine(tmp); > > > > +       else > > > > +               tmp = pgprot_noncached(tmp); > > > > +#endif > > > > +#if defined(__sparc__) > > > > +       tmp = pgprot_noncached(tmp); > > > > +#endif > > > > +       return tmp; > > > > +} > > > > + > > > >   struct dentry *ttm_debugfs_root; > > > > > > > >   static int __init ttm_init(void) > > > > diff --git a/drivers/gpu/drm/ttm/ttm_resource.c > > > > b/drivers/gpu/drm/ttm/ttm_resource.c > > > > index 59e2b7157e41..e05ae7e3d477 100644 > > > > --- a/drivers/gpu/drm/ttm/ttm_resource.c > > > > +++ b/drivers/gpu/drm/ttm/ttm_resource.c > > > > @@ -22,6 +22,10 @@ > > > >    * Authors: Christian König > > > >    */ > > > > > > > > +#include > > > > +#include > > > > +#include > > > > + > > > >   #include > > > >   #include > > > > > > > > @@ -147,3 +151,165 @@ void ttm_resource_manager_debug(struct > > > > ttm_resource_manager *man, > > > >                  man->func->debug(man, p); > > > >   } > > > >   EXPORT_SYMBOL(ttm_resource_manager_debug); > > > > + > > > > +static void ttm_kmap_iter_iomap_map_local(struct ttm_kmap_iter > > > > *iter, > > > > +                                         struct dma_buf_map > > > > *dmap, > > > > +                                         pgoff_t i) > > > > +{ > > > > +       struct ttm_kmap_iter_iomap *iter_io = > > > > +               container_of(iter, typeof(*iter_io), base); > > > > +       void __iomem *addr; > > > > + > > > > +retry: > > > > +       while (i >= iter_io->cache.end) { > > > > +               iter_io->cache.sg = iter_io->cache.sg ? > > > > +                       sg_next(iter_io->cache.sg) : iter_io- > > > > >st->sgl; > > > > +               iter_io->cache.i = iter_io->cache.end; > > > > +               iter_io->cache.end += sg_dma_len(iter_io- > > > > >cache.sg) >> > > > > +                       PAGE_SHIFT; > > > > +               iter_io->cache.offs = sg_dma_address(iter_io- > > > > >cache.sg) - > > > > +                       iter_io->start; > > > > +       } > > > > + > > > > +       if (i < iter_io->cache.i) { > > > > +               iter_io->cache.end = 0; > > > > +               iter_io->cache.sg = NULL; > > > > +               goto retry; > > > > +       } > > > > + > > > > +       addr = io_mapping_map_local_wc(iter_io->iomap, iter_io- > > > > >cache.offs + > > > > +                                      (((resource_size_t)i - > > > > iter_io->cache.i) > > > > +                                       << PAGE_SHIFT)); > > > > +       dma_buf_map_set_vaddr_iomem(dmap, addr); > > > > +} > > > > + > > > > +static void ttm_kmap_iter_iomap_unmap_local(struct > > > > ttm_kmap_iter *iter, > > > > +                                           struct dma_buf_map > > > > *map) > > > > +{ > > > > +       io_mapping_unmap_local(map->vaddr_iomem); > > > > +} > > > > + > > > > +static const struct ttm_kmap_iter_ops ttm_kmap_iter_io_ops = { > > > > +       .map_local =  ttm_kmap_iter_iomap_map_local, > > > > +       .unmap_local = ttm_kmap_iter_iomap_unmap_local, > > > > +       .maps_tt = false, > > > > +}; > > > > + > > > > +/** > > > > + * ttm_kmap_iter_iomap_init - Initialize a struct > > > > ttm_kmap_iter_iomap > > > > + * @iter_io: The struct ttm_kmap_iter_iomap to initialize. > > > > + * @iomap: The struct io_mapping representing the underlying > > > > linear io_memory. > > > > + * @st: sg_table into @iomap, representing the memory of the > > > > struct > > > > + * ttm_resource. > > > > + * @start: Offset that needs to be subtracted from @st to make > > > > + * sg_dma_address(st->sgl) - @start == 0 for @iomap start. > > > > + * > > > > + * Return: Pointer to the embedded struct ttm_kmap_iter. > > > > + */ > > > > +struct ttm_kmap_iter * > > > > +ttm_kmap_iter_iomap_init(struct ttm_kmap_iter_iomap *iter_io, > > > > +                        struct io_mapping *iomap, > > > > +                        struct sg_table *st, > > > > +                        resource_size_t start) > > > > +{ > > > > +       iter_io->base.ops = &ttm_kmap_iter_io_ops; > > > > +       iter_io->iomap = iomap; > > > > +       iter_io->st = st; > > > > +       iter_io->start = start; > > > > +       memset(&iter_io->cache, 0, sizeof(iter_io->cache)); > > > > + > > > > +       return &iter_io->base; > > > > +} > > > > +EXPORT_SYMBOL(ttm_kmap_iter_iomap_init); > > > > + > > > > +/** > > > > + * DOC: Linear io iterator > > > > + * > > > > + * This code should die in the not too near future. Best would > > > > be if we could > > > > + * make io-mapping use memremap for all io memory, and have > > > > memremap > > > > + * implement a kmap_local functionality. We could then strip a > > > > huge amount of > > > > + * code. These linear io iterators are implemented to mimic > > > > old functionality, > > > > + * and they don't use kmap_local semantics at all internally. > > > > Rather ioremap or > > > > + * friends, and at least on 32-bit they add global TLB flushes > > > > and points > > > > + * of failure. > > > > + */ > > > > + > > > > +static void ttm_kmap_iter_linear_io_map_local(struct > > > > ttm_kmap_iter *iter, > > > > +                                             struct > > > > dma_buf_map *dmap, > > > > +                                             pgoff_t i) > > > > +{ > > > > +       struct ttm_kmap_iter_linear_io *iter_io = > > > > +               container_of(iter, typeof(*iter_io), base); > > > > + > > > > +       *dmap = iter_io->dmap; > > > > +       dma_buf_map_incr(dmap, i * PAGE_SIZE); > > > > +} > > > > + > > > > +static const struct ttm_kmap_iter_ops > > > > ttm_kmap_iter_linear_io_ops = { > > > > +       .map_local =  ttm_kmap_iter_linear_io_map_local, > > > > +       .maps_tt = false, > > > > +}; > > > > + > > > > +struct ttm_kmap_iter * > > > > +ttm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io > > > > *iter_io, > > > > +                            struct ttm_device *bdev, > > > > +                            struct ttm_resource *mem) > > > > +{ > > > > +       int ret; > > > > + > > > > +       ret = ttm_mem_io_reserve(bdev, mem); > > > > +       if (ret) > > > > +               goto out_err; > > > > +       if (!mem->bus.is_iomem) { > > > > +               ret = -EINVAL; > > > > +               goto out_io_free; > > > > +       } > > > > + > > > > +       if (mem->bus.addr) { > > > > +               dma_buf_map_set_vaddr(&iter_io->dmap, mem- > > > > >bus.addr); > > > > +               iter_io->needs_unmap = false; > > > > +       } else { > > > > +               size_t bus_size = (size_t)mem->num_pages << > > > > PAGE_SHIFT; > > > > + > > > > +               iter_io->needs_unmap = true; > > > > +               if (mem->bus.caching == ttm_write_combined) > > > > +                       dma_buf_map_set_vaddr_iomem(&iter_io- > > > > >dmap, > > > > +                                                   > > > > ioremap_wc(mem->bus.offset, > > > > +                                                              > > > > bus_size)); > > > > +               else if (mem->bus.caching == ttm_cached) > > > > +                       dma_buf_map_set_vaddr(&iter_io->dmap, > > > > +                                             memremap(mem- > > > > >bus.offset, bus_size, > > > > +                                                      > > > > MEMREMAP_WB)); > > > The comments in set_vaddr suggest that this is meant for > > > system-memory. Does that actually matter or is it just about not > > > losing the __iomem annotation on platforms where it matters? > > > > Yes, it's the latter. dma_buf_map() is relatively new and the > > author > > probably didn't think about the case of cached iomem, which is used > > by, > > for example, vmwgfx. > > > > > Apparently cached device local is a thing. Also should this not > > > be > > > wrapped in CONFIG_X86? > > > > Both dma_buf_map() and memremap are generic, I think, I guess > > memremap > > would return NULL if it's not supported. > > It looks like memremap just wraps ioremap_cache, but since it also > discards the __iomem annotation should we be doing that universally? > Also not sure if ioremap_cache is universally supported, so wrapping > in CONFIG_X86 and falling back to plain ioremap() might be needed? Or > at least that looks like roughly what the previous code was doing? > Not > too sure tbh. > I think the long term goal is to use memremap all over the place, to just not have to bother with the __iomem annotation. But to do that io- mapping.h needs to support memremap. But for now we need to be strict about __iomem unless we're in arch specific code. That's why that dma_buf_map thing was created, but TTM memcpy was never fully adapted. As for limited arch support for memremap cached, It looks like we only need to or in "backup" mapping modes in the memremap flags, and we'd mimic the previous behaviour. /Thomas > > > > /Thomas > > > > From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9CD9BC2B9F8 for ; Tue, 25 May 2021 10:08:08 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (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 587DB6140E for ; Tue, 25 May 2021 10:08:08 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 587DB6140E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id BF7636E9E4; Tue, 25 May 2021 10:08:02 +0000 (UTC) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by gabe.freedesktop.org (Postfix) with ESMTPS id CCAF66E9E3; Tue, 25 May 2021 10:08:00 +0000 (UTC) IronPort-SDR: D3OkIHi+CsJmWb3jftFVSVEQzdS6M/y0jaJM1Zae68ef6WdnTcJztv/TQ91vkd6A5TJhXEsnog ywXbAtrFKKCA== X-IronPort-AV: E=McAfee;i="6200,9189,9994"; a="266050123" X-IronPort-AV: E=Sophos;i="5.82,328,1613462400"; d="scan'208";a="266050123" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 May 2021 03:07:59 -0700 IronPort-SDR: FdzQSl8KiSA6Av1UDf0hMpmPETx8ii8XjM7SpbUTM9+ch8mW5vs7EIdfaBWkfcdPzZQNASn3sv LRu53tddM4kw== X-IronPort-AV: E=Sophos;i="5.82,328,1613462400"; d="scan'208";a="630170655" Received: from vkubarev-mobl1.ccr.corp.intel.com ([10.249.254.43]) by fmsmga006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 May 2021 03:07:58 -0700 Message-ID: From: Thomas =?ISO-8859-1?Q?Hellstr=F6m?= To: Matthew Auld Date: Tue, 25 May 2021 12:07:55 +0200 In-Reply-To: References: <20210521153253.518037-1-thomas.hellstrom@linux.intel.com> <20210521153253.518037-7-thomas.hellstrom@linux.intel.com> <2cc9a60c-4360-40b6-8712-1e50b7bbfd03@linux.intel.com> User-Agent: Evolution 3.38.4 (3.38.4-1.fc33) MIME-Version: 1.0 Subject: Re: [Intel-gfx] [PATCH v3 06/12] drm/ttm: Add a generic TTM memcpy move for page-based iomem X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Intel Graphics Development , Christian =?ISO-8859-1?Q?K=F6nig?= , ML dri-devel Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" T24gVHVlLCAyMDIxLTA1LTI1IGF0IDEwOjU4ICswMTAwLCBNYXR0aGV3IEF1bGQgd3JvdGU6Cj4g T24gVHVlLCAyNSBNYXkgMjAyMSBhdCAxMDozMiwgVGhvbWFzIEhlbGxzdHLDtm0KPiA8dGhvbWFz LmhlbGxzdHJvbUBsaW51eC5pbnRlbC5jb20+IHdyb3RlOgo+ID4gCj4gPiAKPiA+IE9uIDUvMjUv MjEgMTE6MTggQU0sIE1hdHRoZXcgQXVsZCB3cm90ZToKPiA+ID4gT24gRnJpLCAyMSBNYXkgMjAy MSBhdCAxNjozMywgVGhvbWFzIEhlbGxzdHLDtm0KPiA+ID4gPHRob21hcy5oZWxsc3Ryb21AbGlu dXguaW50ZWwuY29tPiB3cm90ZToKPiA+ID4gPiBUaGUgaW50ZXJuYWwgdHRtX2JvX3V0aWwgbWVt Y3B5IHVzZXMgaW9yZW1hcCBmdW5jdGlvbmFsaXR5LCBhbmQKPiA+ID4gPiB3aGlsZSBpdAo+ID4g PiA+IHByb2JhYmx5IG1pZ2h0IGJlIHBvc3NpYmxlIHRvIHVzZSBpdCBmb3IgY29weWluZyBpbi0g YW5kIG91dCBvZgo+ID4gPiA+IHNnbGlzdCByZXByZXNlbnRlZCBpbyBtZW1vcnksIHVzaW5nIGlv X21lbV9yZXNlcnZlKCkgLwo+ID4gPiA+IGlvX21lbV9mcmVlKCkKPiA+ID4gPiBjYWxsYmFja3Ms IHRoYXQgd291bGQgY2F1c2UgcHJvYmxlbXMgd2l0aCBmYXVsdCgpLgo+ID4gPiA+IEluc3RlYWQs IGltcGxlbWVudCBhIG1ldGhvZCBtYXBwaW5nIHBhZ2UtYnktcGFnZSB1c2luZwo+ID4gPiA+IGtt YXBfbG9jYWwoKQo+ID4gPiA+IHNlbWFudGljcy4gQXMgYW4gYWRkaXRpb25hbCBiZW5lZml0IHdl IHRoZW4gYXZvaWQgdGhlCj4gPiA+ID4gb2NjYXNpb25hbCBnbG9iYWwKPiA+ID4gPiBUTEIgZmx1 c2hlcyBvZiBpb3JlbWFwKCkgYW5kIGNvbnN1bWluZyBpb3JlbWFwIHNwYWNlLAo+ID4gPiA+IGVs aW1pbmF0aW9uIG9mIGEKPiA+ID4gPiBjcml0aWNhbCBwb2ludCBvZiBmYWlsdXJlIGFuZCB3aXRo IGEgc2xpZ2h0IGNoYW5nZSBvZiBzZW1hbnRpY3MKPiA+ID4gPiB3ZSBjb3VsZAo+ID4gPiA+IGFs c28gcHVzaCB0aGUgbWVtY3B5IG91dCBhc3luYyBmb3IgdGVzdGluZyBhbmQgYXN5bmMgZHJpdmVy Cj4gPiA+ID4gZGV2ZWxvcG1lbnQKPiA+ID4gPiBwdXJwb3Nlcy4KPiA+ID4gPiAKPiA+ID4gPiBB IHNwZWNpYWwgbGluZWFyIGlvbWVtIGl0ZXJhdG9yIGlzIGludHJvZHVjZWQgaW50ZXJuYWxseSB0 bwo+ID4gPiA+IG1pbWljIHRoZQo+ID4gPiA+IG9sZCBpb3JlbWFwIGJlaGF2aW91ciBmb3IgY29k ZS1wYXRocyB0aGF0IGNhbid0IGltbWVkaWF0ZWx5IGJlCj4gPiA+ID4gcG9ydGVkCj4gPiA+ID4g b3Zlci4gVGhpcyBhZGRzIHRvIHRoZSBjb2RlIHNpemUgYW5kIHNob3VsZCBiZSBjb25zaWRlcmVk IGEKPiA+ID4gPiB0ZW1wb3JhcnkKPiA+ID4gPiBzb2x1dGlvbi4KPiA+ID4gPiAKPiA+ID4gPiBM b29raW5nIGF0IHRoZSBjb2RlIHdlIGhhdmUgYSBsb3Qgb2YgY2hlY2tzIGZvciBpb21hcCB0YWdn ZWQKPiA+ID4gPiBwb2ludGVycy4KPiA+ID4gPiBJZGVhbGx5IHdlIHNob3VsZCBleHRlbmQgdGhl IGNvcmUgbWVtcmVtYXAgZnVuY3Rpb25zIHRvIGFsc28KPiA+ID4gPiBhY2NlcHQKPiA+ID4gPiB1 bmNhY2hlZCBtZW1vcnkgYW5kIGttYXBfbG9jYWwgZnVuY3Rpb25hbGl0eS4gVGhlbiB3ZSBjb3Vs ZAo+ID4gPiA+IHN0cmlwIGEKPiA+ID4gPiBsb3Qgb2YgY29kZS4KPiA+ID4gPiAKPiA+ID4gPiBD YzogQ2hyaXN0aWFuIEvDtm5pZyA8Y2hyaXN0aWFuLmtvZW5pZ0BhbWQuY29tPgo+ID4gPiA+IFNp Z25lZC1vZmYtYnk6IFRob21hcyBIZWxsc3Ryw7ZtIDwKPiA+ID4gPiB0aG9tYXMuaGVsbHN0cm9t QGxpbnV4LmludGVsLmNvbT4KPiA+ID4gPiAtLS0KPiA+ID4gPiB2MzoKPiA+ID4gPiAtIFNwbGl0 IHVwIGluIHZhcmlvdXMgVFRNIGZpbGVzIGFuZCBhZGRyZXNzZWQgcmV2aWV3IGNvbW1lbnRzCj4g PiA+ID4gYnkKPiA+ID4gPiDCoMKgIENocmlzdGlhbiBLw7ZuaWcuIFRlc3RlZCBhbmQgZml4ZWQg bGVnYWN5IGlvbWFwIG1lbWNweSBwYXRoCj4gPiA+ID4gb24gaTkxNS4KPiA+ID4gPiAtLS0KPiA+ ID4gPiDCoCBkcml2ZXJzL2dwdS9kcm0vdHRtL3R0bV9ib191dGlsLmPCoCB8IDI3OCArKysrKysr KysrLS0tLS0tLS0tLQo+ID4gPiA+IC0tLS0tLS0tLQo+ID4gPiA+IMKgIGRyaXZlcnMvZ3B1L2Ry bS90dG0vdHRtX21vZHVsZS5jwqDCoCB8wqAgMzUgKysrKwo+ID4gPiA+IMKgIGRyaXZlcnMvZ3B1 L2RybS90dG0vdHRtX3Jlc291cmNlLmMgfCAxNjYgKysrKysrKysrKysrKysrKysKPiA+ID4gPiDC oCBkcml2ZXJzL2dwdS9kcm0vdHRtL3R0bV90dC5jwqDCoMKgwqDCoMKgIHzCoCA0MiArKysrKwo+ ID4gPiA+IMKgIGluY2x1ZGUvZHJtL3R0bS90dG1fYm9fZHJpdmVyLmjCoMKgwqAgfMKgIDI4ICsr Kwo+ID4gPiA+IMKgIGluY2x1ZGUvZHJtL3R0bS90dG1fY2FjaGluZy5owqDCoMKgwqDCoCB8wqDC oCAyICsKPiA+ID4gPiDCoCBpbmNsdWRlL2RybS90dG0vdHRtX2ttYXBfaXRlci5owqDCoMKgIHzC oCA2MSArKysrKysrCj4gPiA+ID4gwqAgaW5jbHVkZS9kcm0vdHRtL3R0bV9yZXNvdXJjZS5owqDC oMKgwqAgfMKgIDYxICsrKysrKysKPiA+ID4gPiDCoCBpbmNsdWRlL2RybS90dG0vdHRtX3R0LmjC oMKgwqDCoMKgwqDCoMKgwqDCoCB8wqAgMTYgKysKPiA+ID4gPiDCoCA5IGZpbGVzIGNoYW5nZWQs IDUwOCBpbnNlcnRpb25zKCspLCAxODEgZGVsZXRpb25zKC0pCj4gPiA+ID4gwqAgY3JlYXRlIG1v ZGUgMTAwNjQ0IGluY2x1ZGUvZHJtL3R0bS90dG1fa21hcF9pdGVyLmgKPiA+ID4gPiAKPiA+ID4g PiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL3R0bS90dG1fYm9fdXRpbC5jCj4gPiA+ID4g Yi9kcml2ZXJzL2dwdS9kcm0vdHRtL3R0bV9ib191dGlsLmMKPiA+ID4gPiBpbmRleCBhZThiNjE0 NjA3MjQuLjkxMmNiZThlNjBhMiAxMDA2NDQKPiA+ID4gPiAtLS0gYS9kcml2ZXJzL2dwdS9kcm0v dHRtL3R0bV9ib191dGlsLmMKPiA+ID4gPiArKysgYi9kcml2ZXJzL2dwdS9kcm0vdHRtL3R0bV9i b191dGlsLmMKPiA+ID4gPiBAQCAtNzIsMTkwICs3MiwxMjYgQEAgdm9pZCB0dG1fbWVtX2lvX2Zy ZWUoc3RydWN0IHR0bV9kZXZpY2UKPiA+ID4gPiAqYmRldiwKPiA+ID4gPiDCoMKgwqDCoMKgwqDC oMKgIG1lbS0+YnVzLmFkZHIgPSBOVUxMOwo+ID4gPiA+IMKgIH0KPiA+ID4gPiAKPiA+ID4gPiAt c3RhdGljIGludCB0dG1fcmVzb3VyY2VfaW9yZW1hcChzdHJ1Y3QgdHRtX2RldmljZSAqYmRldiwK PiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBzdHJ1Y3QgdHRtX3Jlc291cmNlICptZW0sCj4gPiA+ID4gLcKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgdm9pZCAqKnZp cnR1YWwpCj4gPiA+ID4gKy8qKgo+ID4gPiA+ICsgKiB0dG1fbW92ZV9tZW1jcHkgLSBIZWxwZXIg dG8gcGVyZm9ybSBhIG1lbWNweSB0dG0gbW92ZQo+ID4gPiA+IG9wZXJhdGlvbi4KPiA+ID4gPiAr ICogQGJvOiBUaGUgc3RydWN0IHR0bV9idWZmZXJfb2JqZWN0Lgo+ID4gPiA+ICsgKiBAbmV3X21l bTogVGhlIHN0cnVjdCB0dG1fcmVzb3VyY2Ugd2UncmUgbW92aW5nIHRvIChjb3B5Cj4gPiA+ID4g ZGVzdGluYXRpb24pLgo+ID4gPiA+ICsgKiBAbmV3X2l0ZXI6IEEgc3RydWN0IHR0bV9rbWFwX2l0 ZXIgcmVwcmVzZW50aW5nIHRoZQo+ID4gPiA+IGRlc3RpbmF0aW9uIHJlc291cmNlLgo+ID4gPiA+ ICsgKiBAc3JjX2l0ZXI6IEEgc3RydWN0IHR0bV9rbWFwX2l0ZXIgcmVwcmVzZW50aW5nIHRoZSBz b3VyY2UKPiA+ID4gPiByZXNvdXJjZS4KPiA+ID4gPiArICoKPiA+ID4gPiArICogVGhpcyBmdW5j dGlvbiBpcyBpbnRlbmRlZCB0byBiZSBhYmxlIHRvIG1vdmUgb3V0IGFzeW5jCj4gPiA+ID4gdW5k ZXIgYQo+ID4gPiA+ICsgKiBkbWEtZmVuY2UgaWYgZGVzaXJlZC4KPiA+ID4gPiArICovCj4gPiA+ ID4gK3ZvaWQgdHRtX21vdmVfbWVtY3B5KHN0cnVjdCB0dG1fYnVmZmVyX29iamVjdCAqYm8sCj4g PiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0cnVjdCB0dG1f cmVzb3VyY2UgKmRzdF9tZW0sCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIHN0cnVjdCB0dG1fa21hcF9pdGVyICpkc3RfaXRlciwKPiA+ID4gPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3RydWN0IHR0bV9rbWFwX2l0ZXIgKnNy Y19pdGVyKQo+ID4gPiA+IMKgIHsKPiA+ID4gPiAtwqDCoMKgwqDCoMKgIGludCByZXQ7Cj4gPiA+ ID4gLcKgwqDCoMKgwqDCoCB2b2lkICphZGRyOwo+ID4gPiA+IC0KPiA+ID4gPiAtwqDCoMKgwqDC oMKgICp2aXJ0dWFsID0gTlVMTDsKPiA+ID4gPiAtwqDCoMKgwqDCoMKgIHJldCA9IHR0bV9tZW1f aW9fcmVzZXJ2ZShiZGV2LCBtZW0pOwo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgaWYgKHJldCB8fCAh bWVtLT5idXMuaXNfaW9tZW0pCj4gPiA+ID4gLcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg cmV0dXJuIHJldDsKPiA+ID4gPiArwqDCoMKgwqDCoMKgIGNvbnN0IHN0cnVjdCB0dG1fa21hcF9p dGVyX29wcyAqZHN0X29wcyA9IGRzdF9pdGVyLQo+ID4gPiA+ID5vcHM7Cj4gPiA+ID4gK8KgwqDC oMKgwqDCoCBjb25zdCBzdHJ1Y3QgdHRtX2ttYXBfaXRlcl9vcHMgKnNyY19vcHMgPSBzcmNfaXRl ci0KPiA+ID4gPiA+b3BzOwo+ID4gPiA+ICvCoMKgwqDCoMKgwqAgc3RydWN0IHR0bV90dCAqdHRt ID0gYm8tPnR0bTsKPiA+ID4gPiArwqDCoMKgwqDCoMKgIHN0cnVjdCBkbWFfYnVmX21hcCBzcmNf bWFwLCBkc3RfbWFwOwo+ID4gPiA+ICvCoMKgwqDCoMKgwqAgcGdvZmZfdCBpOwo+ID4gPiA+IAo+ ID4gPiA+IC3CoMKgwqDCoMKgwqAgaWYgKG1lbS0+YnVzLmFkZHIpIHsKPiA+ID4gPiAtwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBhZGRyID0gbWVtLT5idXMuYWRkcjsKPiA+ID4gPiAtwqDC oMKgwqDCoMKgIH0gZWxzZSB7Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg c2l6ZV90IGJ1c19zaXplID0gKHNpemVfdCltZW0tPm51bV9wYWdlcyA8PAo+ID4gPiA+IFBBR0Vf U0hJRlQ7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCAvKiBTaW5nbGUgVFRNIG1vdmUuIE5PUCAqLwo+ ID4gPiA+ICvCoMKgwqDCoMKgwqAgaWYgKGRzdF9vcHMtPm1hcHNfdHQgJiYgc3JjX29wcy0+bWFw c190dCkKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZXR1cm47Cj4gPiA+ ID4gCj4gPiA+ID4gLcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgKG1lbS0+YnVzLmNh Y2hpbmcgPT0gdHRtX3dyaXRlX2NvbWJpbmVkKQo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBhZGRyID0gaW9yZW1hcF93YyhtZW0tPmJ1cy5vZmZz ZXQsCj4gPiA+ID4gYnVzX3NpemUpOwo+ID4gPiA+IC0jaWZkZWYgQ09ORklHX1g4Ngo+ID4gPiA+ IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGVsc2UgaWYgKG1lbS0+YnVzLmNhY2hpbmcg PT0gdHRtX2NhY2hlZCkKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgYWRkciA9IGlvcmVtYXBfY2FjaGUobWVtLT5idXMub2Zmc2V0LAo+ID4gPiA+ IGJ1c19zaXplKTsKPiA+ID4gPiAtI2VuZGlmCj4gPiA+ID4gLcKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgZWxzZQo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBhZGRyID0gaW9yZW1hcChtZW0tPmJ1cy5vZmZzZXQsCj4gPiA+ID4gYnVzX3Np emUpOwo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGlmICghYWRkcikgewo+ ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB0dG1f bWVtX2lvX2ZyZWUoYmRldiwgbWVtKTsKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIC1FTk9NRU07Cj4gPiA+ID4gK8KgwqDCoMKgwqDC oCAvKiBEb24ndCBtb3ZlIG5vbmV4aXN0ZW50IGRhdGEuIENsZWFyIGRlc3RpbmF0aW9uCj4gPiA+ ID4gaW5zdGVhZC4gKi8KPiA+ID4gPiArwqDCoMKgwqDCoMKgIGlmIChzcmNfb3BzLT5tYXBzX3R0 ICYmICghdHRtIHx8Cj4gPiA+ID4gIXR0bV90dF9pc19wb3B1bGF0ZWQodHRtKSkpIHsKPiA+ID4g PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAodHRtICYmICEodHRtLT5wYWdlX2Zs YWdzICYKPiA+ID4gPiBUVE1fUEFHRV9GTEFHX1pFUk9fQUxMT0MpKQo+ID4gPiA+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZXR1cm47Cj4gPiA+ID4gKwo+ ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGZvciAoaSA9IDA7IGkgPCBkc3Rf bWVtLT5udW1fcGFnZXM7ICsraSkgewo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCBkc3Rfb3BzLT5tYXBfbG9jYWwoZHN0X2l0ZXIsICZkc3RfbWFw LAo+ID4gPiA+IGkpOwo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBpZiAoZHN0X21hcC5pc19pb21lbSkKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIG1lbXNldF9pbyhk c3RfbWFwLnZhZGRyX2lvbWVtLAo+ID4gPiA+IDAsIFBBR0VfU0laRSk7Cj4gPiA+ID4gK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGVsc2UKPiA+ID4gPiArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IG1lbXNldChkc3RfbWFwLnZhZGRyLCAwLAo+ID4gPiA+IFBBR0VfU0laRSk7Cj4gPiA+ID4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGlmIChkc3Rfb3BzLT51 bm1hcF9sb2NhbCkKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGRzdF9vcHMtPnVubWFwX2xvY2FsKGRzdF9pdGVyLAo+ ID4gPiA+ICZkc3RfbWFwKTsKPiA+ID4gPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCB9Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuOwo+ID4gPiA+ IMKgwqDCoMKgwqDCoMKgwqAgfQo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgKnZpcnR1YWwgPSBhZGRy Owo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgcmV0dXJuIDA7Cj4gPiA+ID4gLX0KPiA+ID4gPiAtCj4g PiA+ID4gLXN0YXRpYyB2b2lkIHR0bV9yZXNvdXJjZV9pb3VubWFwKHN0cnVjdCB0dG1fZGV2aWNl ICpiZGV2LAo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgc3RydWN0IHR0bV9yZXNvdXJjZSAqbWVtLAo+ID4gPiA+IC3C oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqAgdm9pZCAqdmlydHVhbCkKPiA+ID4gPiAtewo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgaWYgKHZp cnR1YWwgJiYgbWVtLT5idXMuYWRkciA9PSBOVUxMKQo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIGlvdW5tYXAodmlydHVhbCk7Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoCB0dG1f bWVtX2lvX2ZyZWUoYmRldiwgbWVtKTsKPiA+ID4gPiAtfQo+ID4gPiA+IC0KPiA+ID4gPiAtc3Rh dGljIGludCB0dG1fY29weV9pb19wYWdlKHZvaWQgKmRzdCwgdm9pZCAqc3JjLCB1bnNpZ25lZAo+ ID4gPiA+IGxvbmcgcGFnZSkKPiA+ID4gPiAtewo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgdWludDMy X3QgKmRzdFAgPQo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoCAodWludDMyX3QgKikgKCh1 bnNpZ25lZCBsb25nKWRzdCArIChwYWdlIDw8Cj4gPiA+ID4gUEFHRV9TSElGVCkpOwo+ID4gPiA+ IC3CoMKgwqDCoMKgwqAgdWludDMyX3QgKnNyY1AgPQo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKg wqDCoCAodWludDMyX3QgKikgKCh1bnNpZ25lZCBsb25nKXNyYyArIChwYWdlIDw8Cj4gPiA+ID4g UEFHRV9TSElGVCkpOwo+ID4gPiA+IC0KPiA+ID4gPiAtwqDCoMKgwqDCoMKgIGludCBpOwo+ID4g PiA+IC3CoMKgwqDCoMKgwqAgZm9yIChpID0gMDsgaSA8IFBBR0VfU0laRSAvIHNpemVvZih1aW50 MzJfdCk7ICsraSkKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpb3dyaXRl MzIoaW9yZWFkMzIoc3JjUCsrKSwgZHN0UCsrKTsKPiA+ID4gPiAtwqDCoMKgwqDCoMKgIHJldHVy biAwOwo+ID4gPiA+IC19Cj4gPiA+ID4gLQo+ID4gPiA+IC1zdGF0aWMgaW50IHR0bV9jb3B5X2lv X3R0bV9wYWdlKHN0cnVjdCB0dG1fdHQgKnR0bSwgdm9pZCAqc3JjLAo+ID4gPiA+IC3CoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgdW5z aWduZWQgbG9uZyBwYWdlLAo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcGdwcm90X3QgcHJvdCkKPiA+ID4gPiAtewo+ ID4gPiA+IC3CoMKgwqDCoMKgwqAgc3RydWN0IHBhZ2UgKmQgPSB0dG0tPnBhZ2VzW3BhZ2VdOwo+ ID4gPiA+IC3CoMKgwqDCoMKgwqAgdm9pZCAqZHN0Owo+ID4gPiA+IC0KPiA+ID4gPiAtwqDCoMKg wqDCoMKgIGlmICghZCkKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZXR1 cm4gLUVOT01FTTsKPiA+ID4gPiAtCj4gPiA+ID4gLcKgwqDCoMKgwqDCoCBzcmMgPSAodm9pZCAq KSgodW5zaWduZWQgbG9uZylzcmMgKyAocGFnZSA8PAo+ID4gPiA+IFBBR0VfU0hJRlQpKTsKPiA+ ID4gPiAtwqDCoMKgwqDCoMKgIGRzdCA9IGttYXBfYXRvbWljX3Byb3QoZCwgcHJvdCk7Cj4gPiA+ ID4gLcKgwqDCoMKgwqDCoCBpZiAoIWRzdCkKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCByZXR1cm4gLUVOT01FTTsKPiA+ID4gPiAtCj4gPiA+ID4gLcKgwqDCoMKgwqDCoCBt ZW1jcHlfZnJvbWlvKGRzdCwgc3JjLCBQQUdFX1NJWkUpOwo+ID4gPiA+IC0KPiA+ID4gPiAtwqDC oMKgwqDCoMKgIGt1bm1hcF9hdG9taWMoZHN0KTsKPiA+ID4gPiAtCj4gPiA+ID4gLcKgwqDCoMKg wqDCoCByZXR1cm4gMDsKPiA+ID4gPiAtfQo+ID4gPiA+IC0KPiA+ID4gPiAtc3RhdGljIGludCB0 dG1fY29weV90dG1faW9fcGFnZShzdHJ1Y3QgdHRtX3R0ICp0dG0sIHZvaWQgKmRzdCwKPiA+ID4g PiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIHVuc2lnbmVkIGxvbmcgcGFnZSwKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHBncHJvdF90IHByb3QpCj4g PiA+ID4gLXsKPiA+ID4gPiAtwqDCoMKgwqDCoMKgIHN0cnVjdCBwYWdlICpzID0gdHRtLT5wYWdl c1twYWdlXTsKPiA+ID4gPiAtwqDCoMKgwqDCoMKgIHZvaWQgKnNyYzsKPiA+ID4gPiAtCj4gPiA+ ID4gLcKgwqDCoMKgwqDCoCBpZiAoIXMpCj4gPiA+ID4gLcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgcmV0dXJuIC1FTk9NRU07Cj4gPiA+ID4gLQo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgZHN0 ID0gKHZvaWQgKikoKHVuc2lnbmVkIGxvbmcpZHN0ICsgKHBhZ2UgPDwKPiA+ID4gPiBQQUdFX1NI SUZUKSk7Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoCBzcmMgPSBrbWFwX2F0b21pY19wcm90KHMsIHBy b3QpOwo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgaWYgKCFzcmMpCj4gPiA+ID4gLcKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIC1FTk9NRU07Cj4gPiA+ID4gCj4gPiA+ID4gLcKgwqDC oMKgwqDCoCBtZW1jcHlfdG9pbyhkc3QsIHNyYywgUEFHRV9TSVpFKTsKPiA+ID4gPiAtCj4gPiA+ ID4gLcKgwqDCoMKgwqDCoCBrdW5tYXBfYXRvbWljKHNyYyk7Cj4gPiA+ID4gK8KgwqDCoMKgwqDC oCBmb3IgKGkgPSAwOyBpIDwgZHN0X21lbS0+bnVtX3BhZ2VzOyArK2kpIHsKPiA+ID4gPiArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkc3Rfb3BzLT5tYXBfbG9jYWwoZHN0X2l0ZXIsICZk c3RfbWFwLCBpKTsKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzcmNfb3Bz LT5tYXBfbG9jYWwoc3JjX2l0ZXIsICZzcmNfbWFwLCBpKTsKPiA+ID4gPiArCj4gPiA+ID4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgKCFzcmNfbWFwLmlzX2lvbWVtICYmICFkc3Rf bWFwLmlzX2lvbWVtKSB7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIG1lbWNweShkc3RfbWFwLnZhZGRyLCBzcmNfbWFwLnZhZGRyLAo+ID4gPiA+ IFBBR0VfU0laRSk7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgfSBlbHNl IGlmICghc3JjX21hcC5pc19pb21lbSkgewo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkbWFfYnVmX21hcF9tZW1jcHlfdG8oJmRzdF9tYXAsCj4g PiA+ID4gc3JjX21hcC52YWRkciwKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCBQQUdFX1NJWkUpOwo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIH0g ZWxzZSBpZiAoIWRzdF9tYXAuaXNfaW9tZW0pIHsKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgbWVtY3B5X2Zyb21pbyhkc3RfbWFwLnZhZGRyLAo+ ID4gPiA+IHNyY19tYXAudmFkZHJfaW9tZW0sCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBQQUdF X1NJWkUpOwo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIH0gZWxzZSB7Cj4g PiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGludCBq Owo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB1 MzIgX19pb21lbSAqc3JjID0gc3JjX21hcC52YWRkcl9pb21lbTsKPiA+ID4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgdTMyIF9faW9tZW0gKmRzdCA9IGRz dF9tYXAudmFkZHJfaW9tZW07Cj4gPiA+ID4gCj4gPiA+ID4gLcKgwqDCoMKgwqDCoCByZXR1cm4g MDsKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg Zm9yIChqID0gMDsgaiA8IChQQUdFX1NJWkUgPj4gMik7ICsraikKPiA+ID4gSU1PIFBBR0VfU0la RSAvIHNpemVvZih1MzIpIGlzIGVhc2llciB0byB1bmRlcnN0YW5kLgo+ID4gCj4gPiBPSywgd2ls bCBmaXguCj4gPiAKPiA+IAo+ID4gPiAKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGlvd3JpdGUzMihpb3JlYWQzMihz cmMrKyksCj4gPiA+ID4gZHN0KyspOwo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgIH0KPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAoc3JjX29wcy0+ dW5tYXBfbG9jYWwpCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIHNyY19vcHMtPnVubWFwX2xvY2FsKHNyY19pdGVyLAo+ID4gPiA+ICZzcmNfbWFw KTsKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAoZHN0X29wcy0+dW5t YXBfbG9jYWwpCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIGRzdF9vcHMtPnVubWFwX2xvY2FsKGRzdF9pdGVyLAo+ID4gPiA+ICZkc3RfbWFwKTsK PiA+ID4gPiArwqDCoMKgwqDCoMKgIH0KPiA+ID4gPiDCoCB9Cj4gPiA+ID4gK0VYUE9SVF9TWU1C T0wodHRtX21vdmVfbWVtY3B5KTsKPiA+ID4gPiAKPiA+ID4gPiDCoCBpbnQgdHRtX2JvX21vdmVf bWVtY3B5KHN0cnVjdCB0dG1fYnVmZmVyX29iamVjdCAqYm8sCj4gPiA+ID4gwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3QgdHRtX29wZXJhdGlvbl9j dHggKmN0eCwKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgIHN0cnVjdCB0dG1fcmVzb3VyY2UgKm5ld19tZW0pCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3QgdHRtX3Jlc291cmNlICpkc3RfbWVt KQo+ID4gPiA+IMKgIHsKPiA+ID4gPiDCoMKgwqDCoMKgwqDCoMKgIHN0cnVjdCB0dG1fZGV2aWNl ICpiZGV2ID0gYm8tPmJkZXY7Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoCBzdHJ1Y3QgdHRtX3Jlc291 cmNlX21hbmFnZXIgKm1hbiA9Cj4gPiA+ID4gdHRtX21hbmFnZXJfdHlwZShiZGV2LCBuZXdfbWVt LT5tZW1fdHlwZSk7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCBzdHJ1Y3QgdHRtX3Jlc291cmNlX21h bmFnZXIgKmRzdF9tYW4gPQo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHR0 bV9tYW5hZ2VyX3R5cGUoYm8tPmJkZXYsIGRzdF9tZW0tPm1lbV90eXBlKTsKPiA+ID4gPiDCoMKg wqDCoMKgwqDCoMKgIHN0cnVjdCB0dG1fdHQgKnR0bSA9IGJvLT50dG07Cj4gPiA+ID4gLcKgwqDC oMKgwqDCoCBzdHJ1Y3QgdHRtX3Jlc291cmNlICpvbGRfbWVtID0gJmJvLT5tZW07Cj4gPiA+ID4g LcKgwqDCoMKgwqDCoCBzdHJ1Y3QgdHRtX3Jlc291cmNlIG9sZF9jb3B5ID0gKm9sZF9tZW07Cj4g PiA+ID4gLcKgwqDCoMKgwqDCoCB2b2lkICpvbGRfaW9tYXA7Cj4gPiA+ID4gLcKgwqDCoMKgwqDC oCB2b2lkICpuZXdfaW9tYXA7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCBzdHJ1Y3QgdHRtX3Jlc291 cmNlICpzcmNfbWVtID0gJmJvLT5tZW07Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCBzdHJ1Y3QgdHRt X3Jlc291cmNlX21hbmFnZXIgKnNyY19tYW4gPQo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIHR0bV9tYW5hZ2VyX3R5cGUoYmRldiwgc3JjX21lbS0+bWVtX3R5cGUpOwo+ID4g PiA+ICvCoMKgwqDCoMKgwqAgc3RydWN0IHR0bV9yZXNvdXJjZSBzcmNfY29weSA9ICpzcmNfbWVt Owo+ID4gPiA+ICvCoMKgwqDCoMKgwqAgdW5pb24gewo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIHN0cnVjdCB0dG1fa21hcF9pdGVyX3R0IHR0Owo+ID4gPiA+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0cnVjdCB0dG1fa21hcF9pdGVyX2xpbmVhcl9pbyBpbzsK PiA+ID4gPiArwqDCoMKgwqDCoMKgIH0gX2RzdF9pdGVyLCBfc3JjX2l0ZXI7Cj4gPiA+ID4gK8Kg wqDCoMKgwqDCoCBzdHJ1Y3QgdHRtX2ttYXBfaXRlciAqZHN0X2l0ZXIsICpzcmNfaXRlcjsKPiA+ ID4gPiDCoMKgwqDCoMKgwqDCoMKgIGludCByZXQ7Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoCB1bnNp Z25lZCBsb25nIGk7Cj4gPiA+ID4gCj4gPiA+ID4gLcKgwqDCoMKgwqDCoCByZXQgPSB0dG1fYm9f d2FpdF9jdHgoYm8sIGN0eCk7Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoCBpZiAocmV0KQo+ID4gPiA+ IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldHVybiByZXQ7Cj4gPiA+ID4gLQo+ID4g PiA+IC3CoMKgwqDCoMKgwqAgcmV0ID0gdHRtX3Jlc291cmNlX2lvcmVtYXAoYmRldiwgb2xkX21l bSwgJm9sZF9pb21hcCk7Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoCBpZiAocmV0KQo+ID4gPiA+IC3C oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldHVybiByZXQ7Cj4gPiA+ID4gLcKgwqDCoMKg wqDCoCByZXQgPSB0dG1fcmVzb3VyY2VfaW9yZW1hcChiZGV2LCBuZXdfbWVtLCAmbmV3X2lvbWFw KTsKPiA+ID4gPiAtwqDCoMKgwqDCoMKgIGlmIChyZXQpCj4gPiA+ID4gLcKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgZ290byBvdXQ7Cj4gPiA+ID4gLQo+ID4gPiA+IC3CoMKgwqDCoMKgwqAg LyoKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqAgKiBTaW5nbGUgVFRNIG1vdmUuIE5PUC4KPiA+ID4g PiAtwqDCoMKgwqDCoMKgwqAgKi8KPiA+ID4gPiAtwqDCoMKgwqDCoMKgIGlmIChvbGRfaW9tYXAg PT0gTlVMTCAmJiBuZXdfaW9tYXAgPT0gTlVMTCkKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBnb3RvIG91dDI7Cj4gPiA+ID4gLQo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgLyoK PiA+ID4gPiAtwqDCoMKgwqDCoMKgwqAgKiBEb24ndCBtb3ZlIG5vbmV4aXN0ZW50IGRhdGEuIENs ZWFyIGRlc3RpbmF0aW9uCj4gPiA+ID4gaW5zdGVhZC4KPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqAg Ki8KPiA+ID4gPiAtwqDCoMKgwqDCoMKgIGlmIChvbGRfaW9tYXAgPT0gTlVMTCAmJgo+ID4gPiA+ IC3CoMKgwqDCoMKgwqDCoMKgwqDCoCAodHRtID09IE5VTEwgfHwgKCF0dG1fdHRfaXNfcG9wdWxh dGVkKHR0bSkgJiYKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgICEodHRtLT5wYWdlX2ZsYWdzICYKPiA+ID4gPiBUVE1fUEFHRV9G TEFHX1NXQVBQRUQpKSkpIHsKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBt ZW1zZXRfaW8obmV3X2lvbWFwLCAwLCBuZXdfbWVtLQo+ID4gPiA+ID5udW1fcGFnZXMqUEFHRV9T SVpFKTsKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBnb3RvIG91dDI7Cj4g PiA+ID4gLcKgwqDCoMKgwqDCoCB9Cj4gPiA+ID4gLQo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgLyoK PiA+ID4gPiAtwqDCoMKgwqDCoMKgwqAgKiBUVE0gbWlnaHQgYmUgbnVsbCBmb3IgbW92ZXMgd2l0 aGluIHRoZSBzYW1lIHJlZ2lvbi4KPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqAgKi8KPiA+ID4gPiAt wqDCoMKgwqDCoMKgIGlmICh0dG0pIHsKPiA+ID4gPiArwqDCoMKgwqDCoMKgIGlmICh0dG0gJiYg KCh0dG0tPnBhZ2VfZmxhZ3MgJiBUVE1fUEFHRV9GTEFHX1NXQVBQRUQpCj4gPiA+ID4gfHwKPiA+ ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGRzdF9tYW4tPnVzZV90 dCkpIHsKPiA+ID4gPiDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZXQgPSB0dG1f dHRfcG9wdWxhdGUoYmRldiwgdHRtLCBjdHgpOwo+ID4gPiA+IMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIGlmIChyZXQpCj4gPiA+ID4gLcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIGdvdG8gb3V0MTsKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIHJldDsKPiA+ID4gPiDCoMKgwqDCoMKg wqDCoMKgIH0KPiA+ID4gPiAKPiA+ID4gPiAtwqDCoMKgwqDCoMKgIGZvciAoaSA9IDA7IGkgPCBu ZXdfbWVtLT5udW1fcGFnZXM7ICsraSkgewo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIGlmIChvbGRfaW9tYXAgPT0gTlVMTCkgewo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBwZ3Byb3RfdCBwcm90ID0gdHRtX2lvX3Byb3Qo Ym8sCj4gPiA+ID4gb2xkX21lbSwgUEFHRV9LRVJORUwpOwo+ID4gPiA+IC3CoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZXQgPSB0dG1fY29weV90dG1faW9fcGFn ZSh0dG0sCj4gPiA+ID4gbmV3X2lvbWFwLCBpLAo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBwcm90KTsKPiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCB9IGVsc2UgaWYgKG5ld19pb21hcCA9PSBOVUxMKSB7Cj4gPiA+ID4gLcKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHBncHJvdF90IHByb3QgPSB0 dG1faW9fcHJvdChibywKPiA+ID4gPiBuZXdfbWVtLCBQQUdFX0tFUk5FTCk7Cj4gPiA+ID4gLcKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldCA9IHR0bV9jb3B5 X2lvX3R0bV9wYWdlKHR0bSwKPiA+ID4gPiBvbGRfaW9tYXAsIGksCj4gPiA+ID4gLcKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHByb3QpOwo+ID4gPiA+IC3CoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIH0gZWxzZSB7Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldCA9IHR0bV9jb3B5X2lvX3BhZ2UobmV3X2lv bWFwLAo+ID4gPiA+IG9sZF9pb21hcCwgaSk7Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgfQo+ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGlmIChyZXQp Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGdv dG8gb3V0MTsKPiA+ID4gPiArwqDCoMKgwqDCoMKgIGRzdF9pdGVyID0gdHRtX2ttYXBfaXRlcl9s aW5lYXJfaW9faW5pdCgmX2RzdF9pdGVyLmlvLAo+ID4gPiA+IGJkZXYsIGRzdF9tZW0pOwo+ID4g PiA+ICvCoMKgwqDCoMKgwqAgaWYgKFBUUl9FUlIoZHN0X2l0ZXIpID09IC1FSU5WQUwgJiYgZHN0 X21hbi0+dXNlX3R0KQo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGRzdF9p dGVyID0gdHRtX2ttYXBfaXRlcl90dF9pbml0KCZfZHN0X2l0ZXIudHQsCj4gPiA+ID4gYm8tPnR0 bSk7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCBpZiAoSVNfRVJSKGRzdF9pdGVyKSkKPiA+ID4gPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZXR1cm4gUFRSX0VSUihkc3RfaXRlcik7Cj4g PiA+ID4gKwo+ID4gPiA+ICvCoMKgwqDCoMKgwqAgc3JjX2l0ZXIgPSB0dG1fa21hcF9pdGVyX2xp bmVhcl9pb19pbml0KCZfc3JjX2l0ZXIuaW8sCj4gPiA+ID4gYmRldiwgc3JjX21lbSk7Cj4gPiA+ ID4gK8KgwqDCoMKgwqDCoCBpZiAoUFRSX0VSUihzcmNfaXRlcikgPT0gLUVJTlZBTCAmJiBzcmNf bWFuLT51c2VfdHQpCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3JjX2l0 ZXIgPSB0dG1fa21hcF9pdGVyX3R0X2luaXQoJl9zcmNfaXRlci50dCwKPiA+ID4gPiBiby0+dHRt KTsKPiA+ID4gPiArwqDCoMKgwqDCoMKgIGlmIChJU19FUlIoc3JjX2l0ZXIpKSB7Cj4gPiA+ID4g K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0ID0gUFRSX0VSUihzcmNfaXRlcik7Cj4g PiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZ290byBvdXRfc3JjX2l0ZXI7Cj4g PiA+ID4gwqDCoMKgwqDCoMKgwqDCoCB9Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoCBtYigpOwo+ID4g PiA+IC1vdXQyOgo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgb2xkX2NvcHkgPSAqb2xkX21lbTsKPiA+ ID4gPiAKPiA+ID4gPiAtwqDCoMKgwqDCoMKgIHR0bV9ib19hc3NpZ25fbWVtKGJvLCBuZXdfbWVt KTsKPiA+ID4gPiAtCj4gPiA+ID4gLcKgwqDCoMKgwqDCoCBpZiAoIW1hbi0+dXNlX3R0KQo+ID4g PiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHR0bV9ib190dF9kZXN0cm95KGJvKTsK PiA+ID4gPiArwqDCoMKgwqDCoMKgIHR0bV9tb3ZlX21lbWNweShibywgZHN0X21lbSwgZHN0X2l0 ZXIsIHNyY19pdGVyKTsKPiA+ID4gPiArwqDCoMKgwqDCoMKgIHNyY19jb3B5ID0gKnNyY19tZW07 Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCB0dG1fYm9fbW92ZV9zeW5jX2NsZWFudXAoYm8sIGRzdF9t ZW0pOwo+ID4gPiA+IAo+ID4gPiA+IC1vdXQxOgo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgdHRtX3Jl c291cmNlX2lvdW5tYXAoYmRldiwgb2xkX21lbSwgbmV3X2lvbWFwKTsKPiA+ID4gPiAtb3V0Ogo+ ID4gPiA+IC3CoMKgwqDCoMKgwqAgdHRtX3Jlc291cmNlX2lvdW5tYXAoYmRldiwgJm9sZF9jb3B5 LCBvbGRfaW9tYXApOwo+ID4gPiA+ICvCoMKgwqDCoMKgwqAgaWYgKCFzcmNfaXRlci0+b3BzLT5t YXBzX3R0KQo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHR0bV9rbWFwX2l0 ZXJfbGluZWFyX2lvX2ZpbmkoJl9zcmNfaXRlci5pbywKPiA+ID4gPiBiZGV2LCAmc3JjX2NvcHkp Owo+ID4gPiA+ICtvdXRfc3JjX2l0ZXI6Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCBpZiAoIWRzdF9p dGVyLT5vcHMtPm1hcHNfdHQpCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg dHRtX2ttYXBfaXRlcl9saW5lYXJfaW9fZmluaSgmX2RzdF9pdGVyLmlvLAo+ID4gPiA+IGJkZXYs IGRzdF9tZW0pOwo+ID4gPiA+IAo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgLyoKPiA+ID4gPiAtwqDC oMKgwqDCoMKgwqAgKiBPbiBlcnJvciwga2VlcCB0aGUgbW0gbm9kZSEKPiA+ID4gPiAtwqDCoMKg wqDCoMKgwqAgKi8KPiA+ID4gPiAtwqDCoMKgwqDCoMKgIGlmICghcmV0KQo+ID4gPiA+IC3CoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHR0bV9yZXNvdXJjZV9mcmVlKGJvLCAmb2xkX2NvcHkp Owo+ID4gPiA+IMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIHJldDsKPiA+ID4gPiDCoCB9Cj4gPiA+ ID4gwqAgRVhQT1JUX1NZTUJPTCh0dG1fYm9fbW92ZV9tZW1jcHkpOwo+ID4gPiA+IEBAIC0zMzYs MjcgKzI3Miw3IEBAIHBncHJvdF90IHR0bV9pb19wcm90KHN0cnVjdAo+ID4gPiA+IHR0bV9idWZm ZXJfb2JqZWN0ICpibywgc3RydWN0IHR0bV9yZXNvdXJjZSAqcmVzLAo+ID4gPiA+IMKgwqDCoMKg wqDCoMKgwqAgbWFuID0gdHRtX21hbmFnZXJfdHlwZShiby0+YmRldiwgcmVzLT5tZW1fdHlwZSk7 Cj4gPiA+ID4gwqDCoMKgwqDCoMKgwqDCoCBjYWNoaW5nID0gbWFuLT51c2VfdHQgPyBiby0+dHRt LT5jYWNoaW5nIDogcmVzLQo+ID4gPiA+ID5idXMuY2FjaGluZzsKPiA+ID4gPiAKPiA+ID4gPiAt wqDCoMKgwqDCoMKgIC8qIENhY2hlZCBtYXBwaW5ncyBuZWVkIG5vIGFkanVzdG1lbnQgKi8KPiA+ ID4gPiAtwqDCoMKgwqDCoMKgIGlmIChjYWNoaW5nID09IHR0bV9jYWNoZWQpCj4gPiA+ID4gLcKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIHRtcDsKPiA+ID4gPiAtCj4gPiA+ID4g LSNpZiBkZWZpbmVkKF9faTM4Nl9fKSB8fCBkZWZpbmVkKF9feDg2XzY0X18pCj4gPiA+ID4gLcKg wqDCoMKgwqDCoCBpZiAoY2FjaGluZyA9PSB0dG1fd3JpdGVfY29tYmluZWQpCj4gPiA+ID4gLcKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgdG1wID0gcGdwcm90X3dyaXRlY29tYmluZSh0bXAp Owo+ID4gPiA+IC3CoMKgwqDCoMKgwqAgZWxzZSBpZiAoYm9vdF9jcHVfZGF0YS54ODYgPiAzKQo+ ID4gPiA+IC3CoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHRtcCA9IHBncHJvdF9ub25jYWNo ZWQodG1wKTsKPiA+ID4gPiAtI2VuZGlmCj4gPiA+ID4gLSNpZiBkZWZpbmVkKF9faWE2NF9fKSB8 fCBkZWZpbmVkKF9fYXJtX18pIHx8Cj4gPiA+ID4gZGVmaW5lZChfX2FhcmNoNjRfXykgfHwgXAo+ ID4gPiA+IC3CoMKgwqAgZGVmaW5lZChfX3Bvd2VycGNfXykgfHwgZGVmaW5lZChfX21pcHNfXykK PiA+ID4gPiAtwqDCoMKgwqDCoMKgIGlmIChjYWNoaW5nID09IHR0bV93cml0ZV9jb21iaW5lZCkK PiA+ID4gPiAtwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB0bXAgPSBwZ3Byb3Rfd3JpdGVj b21iaW5lKHRtcCk7Cj4gPiA+ID4gLcKgwqDCoMKgwqDCoCBlbHNlCj4gPiA+ID4gLcKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgdG1wID0gcGdwcm90X25vbmNhY2hlZCh0bXApOwo+ID4gPiA+ IC0jZW5kaWYKPiA+ID4gPiAtI2lmIGRlZmluZWQoX19zcGFyY19fKQo+ID4gPiA+IC3CoMKgwqDC oMKgwqAgdG1wID0gcGdwcm90X25vbmNhY2hlZCh0bXApOwo+ID4gPiA+IC0jZW5kaWYKPiA+ID4g PiAtwqDCoMKgwqDCoMKgIHJldHVybiB0bXA7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCByZXR1cm4g dHRtX3Byb3RfZnJvbV9jYWNoaW5nKGNhY2hpbmcsIHRtcCk7Cj4gPiA+ID4gwqAgfQo+ID4gPiA+ IMKgIEVYUE9SVF9TWU1CT0wodHRtX2lvX3Byb3QpOwo+ID4gPiA+IAo+ID4gPiA+IGRpZmYgLS1n aXQgYS9kcml2ZXJzL2dwdS9kcm0vdHRtL3R0bV9tb2R1bGUuYwo+ID4gPiA+IGIvZHJpdmVycy9n cHUvZHJtL3R0bS90dG1fbW9kdWxlLmMKPiA+ID4gPiBpbmRleCA1NmIwZWZkYmExYTkuLjk5N2M0 NThmNjhhOSAxMDA2NDQKPiA+ID4gPiAtLS0gYS9kcml2ZXJzL2dwdS9kcm0vdHRtL3R0bV9tb2R1 bGUuYwo+ID4gPiA+ICsrKyBiL2RyaXZlcnMvZ3B1L2RybS90dG0vdHRtX21vZHVsZS5jCj4gPiA+ ID4gQEAgLTMxLDEyICszMSw0NyBAQAo+ID4gPiA+IMKgwqAgKi8KPiA+ID4gPiDCoCAjaW5jbHVk ZSA8bGludXgvbW9kdWxlLmg+Cj4gPiA+ID4gwqAgI2luY2x1ZGUgPGxpbnV4L2RldmljZS5oPgo+ ID4gPiA+ICsjaW5jbHVkZSA8bGludXgvcGd0YWJsZS5oPgo+ID4gPiA+IMKgICNpbmNsdWRlIDxs aW51eC9zY2hlZC5oPgo+ID4gPiA+IMKgICNpbmNsdWRlIDxsaW51eC9kZWJ1Z2ZzLmg+Cj4gPiA+ ID4gwqAgI2luY2x1ZGUgPGRybS9kcm1fc3lzZnMuaD4KPiA+ID4gPiArI2luY2x1ZGUgPGRybS90 dG0vdHRtX2NhY2hpbmcuaD4KPiA+ID4gPiAKPiA+ID4gPiDCoCAjaW5jbHVkZSAidHRtX21vZHVs ZS5oIgo+ID4gPiA+IAo+ID4gPiA+ICsvKioKPiA+ID4gPiArICogdHRtX3Byb3RfZnJvbV9jYWNo aW5nIC0gTW9kaWZ5IHRoZSBwYWdlIHByb3RlY3Rpb24KPiA+ID4gPiBhY2NvcmRpbmcgdG8gdGhl Cj4gPiA+ID4gKyAqIHR0bSBjYWNpbmcgbW9kZQo+ID4gPiA+ICsgKiBAY2FjaGluZzogVGhlIHR0 bSBjYWNoaW5nIG1vZGUKPiA+ID4gPiArICogQHRtcDogVGhlIG9yaWdpbmFsIHBhZ2UgcHJvdGVj dGlvbgo+ID4gPiA+ICsgKgo+ID4gPiA+ICsgKiBSZXR1cm46IFRoZSBtb2RpZmllZCBwYWdlIHBy b3RlY3Rpb24KPiA+ID4gPiArICovCj4gPiA+ID4gK3BncHJvdF90IHR0bV9wcm90X2Zyb21fY2Fj aGluZyhlbnVtIHR0bV9jYWNoaW5nIGNhY2hpbmcsCj4gPiA+ID4gcGdwcm90X3QgdG1wKQo+ID4g PiA+ICt7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCAvKiBDYWNoZWQgbWFwcGluZ3MgbmVlZCBubyBh ZGp1c3RtZW50ICovCj4gPiA+ID4gK8KgwqDCoMKgwqDCoCBpZiAoY2FjaGluZyA9PSB0dG1fY2Fj aGVkKQo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldHVybiB0bXA7Cj4g PiA+ID4gKwo+ID4gPiA+ICsjaWYgZGVmaW5lZChfX2kzODZfXykgfHwgZGVmaW5lZChfX3g4Nl82 NF9fKQo+ID4gPiA+ICvCoMKgwqDCoMKgwqAgaWYgKGNhY2hpbmcgPT0gdHRtX3dyaXRlX2NvbWJp bmVkKQo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHRtcCA9IHBncHJvdF93 cml0ZWNvbWJpbmUodG1wKTsKPiA+ID4gPiArwqDCoMKgwqDCoMKgIGVsc2UgaWYgKGJvb3RfY3B1 X2RhdGEueDg2ID4gMykKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB0bXAg PSBwZ3Byb3Rfbm9uY2FjaGVkKHRtcCk7Cj4gPiA+ID4gKyNlbmRpZgo+ID4gPiA+ICsjaWYgZGVm aW5lZChfX2lhNjRfXykgfHwgZGVmaW5lZChfX2FybV9fKSB8fAo+ID4gPiA+IGRlZmluZWQoX19h YXJjaDY0X18pIHx8IFwKPiA+ID4gPiArwqDCoMKgwqDCoMKgIGRlZmluZWQoX19wb3dlcnBjX18p IHx8IGRlZmluZWQoX19taXBzX18pCj4gPiA+ID4gK8KgwqDCoMKgwqDCoCBpZiAoY2FjaGluZyA9 PSB0dG1fd3JpdGVfY29tYmluZWQpCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqAgdG1wID0gcGdwcm90X3dyaXRlY29tYmluZSh0bXApOwo+ID4gPiA+ICvCoMKgwqDCoMKgwqAg ZWxzZQo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHRtcCA9IHBncHJvdF9u b25jYWNoZWQodG1wKTsKPiA+ID4gPiArI2VuZGlmCj4gPiA+ID4gKyNpZiBkZWZpbmVkKF9fc3Bh cmNfXykKPiA+ID4gPiArwqDCoMKgwqDCoMKgIHRtcCA9IHBncHJvdF9ub25jYWNoZWQodG1wKTsK PiA+ID4gPiArI2VuZGlmCj4gPiA+ID4gK8KgwqDCoMKgwqDCoCByZXR1cm4gdG1wOwo+ID4gPiA+ ICt9Cj4gPiA+ID4gKwo+ID4gPiA+IMKgIHN0cnVjdCBkZW50cnkgKnR0bV9kZWJ1Z2ZzX3Jvb3Q7 Cj4gPiA+ID4gCj4gPiA+ID4gwqAgc3RhdGljIGludCBfX2luaXQgdHRtX2luaXQodm9pZCkKPiA+ ID4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL3R0bS90dG1fcmVzb3VyY2UuYwo+ID4g PiA+IGIvZHJpdmVycy9ncHUvZHJtL3R0bS90dG1fcmVzb3VyY2UuYwo+ID4gPiA+IGluZGV4IDU5 ZTJiNzE1N2U0MS4uZTA1YWU3ZTNkNDc3IDEwMDY0NAo+ID4gPiA+IC0tLSBhL2RyaXZlcnMvZ3B1 L2RybS90dG0vdHRtX3Jlc291cmNlLmMKPiA+ID4gPiArKysgYi9kcml2ZXJzL2dwdS9kcm0vdHRt L3R0bV9yZXNvdXJjZS5jCj4gPiA+ID4gQEAgLTIyLDYgKzIyLDEwIEBACj4gPiA+ID4gwqDCoCAq IEF1dGhvcnM6IENocmlzdGlhbiBLw7ZuaWcKPiA+ID4gPiDCoMKgICovCj4gPiA+ID4gCj4gPiA+ ID4gKyNpbmNsdWRlIDxsaW51eC9kbWEtYnVmLW1hcC5oPgo+ID4gPiA+ICsjaW5jbHVkZSA8bGlu dXgvaW8tbWFwcGluZy5oPgo+ID4gPiA+ICsjaW5jbHVkZSA8bGludXgvc2NhdHRlcmxpc3QuaD4K PiA+ID4gPiArCj4gPiA+ID4gwqAgI2luY2x1ZGUgPGRybS90dG0vdHRtX3Jlc291cmNlLmg+Cj4g PiA+ID4gwqAgI2luY2x1ZGUgPGRybS90dG0vdHRtX2JvX2RyaXZlci5oPgo+ID4gPiA+IAo+ID4g PiA+IEBAIC0xNDcsMyArMTUxLDE2NSBAQCB2b2lkIHR0bV9yZXNvdXJjZV9tYW5hZ2VyX2RlYnVn KHN0cnVjdAo+ID4gPiA+IHR0bV9yZXNvdXJjZV9tYW5hZ2VyICptYW4sCj4gPiA+ID4gwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgbWFuLT5mdW5jLT5kZWJ1ZyhtYW4sIHApOwo+ID4g PiA+IMKgIH0KPiA+ID4gPiDCoCBFWFBPUlRfU1lNQk9MKHR0bV9yZXNvdXJjZV9tYW5hZ2VyX2Rl YnVnKTsKPiA+ID4gPiArCj4gPiA+ID4gK3N0YXRpYyB2b2lkIHR0bV9rbWFwX2l0ZXJfaW9tYXBf bWFwX2xvY2FsKHN0cnVjdCB0dG1fa21hcF9pdGVyCj4gPiA+ID4gKml0ZXIsCj4gPiA+ID4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0cnVjdCBkbWFfYnVmX21hcAo+ID4gPiA+ICpkbWFwLAo+ ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBwZ29mZl90IGkpCj4gPiA+ID4gK3sKPiA+ ID4gPiArwqDCoMKgwqDCoMKgIHN0cnVjdCB0dG1fa21hcF9pdGVyX2lvbWFwICppdGVyX2lvID0K PiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBjb250YWluZXJfb2YoaXRlciwg dHlwZW9mKCppdGVyX2lvKSwgYmFzZSk7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCB2b2lkIF9faW9t ZW0gKmFkZHI7Cj4gPiA+ID4gKwo+ID4gPiA+ICtyZXRyeToKPiA+ID4gPiArwqDCoMKgwqDCoMKg IHdoaWxlIChpID49IGl0ZXJfaW8tPmNhY2hlLmVuZCkgewo+ID4gPiA+ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIGl0ZXJfaW8tPmNhY2hlLnNnID0gaXRlcl9pby0+Y2FjaGUuc2cgPwo+ ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzZ19u ZXh0KGl0ZXJfaW8tPmNhY2hlLnNnKSA6IGl0ZXJfaW8tCj4gPiA+ID4gPnN0LT5zZ2w7Cj4gPiA+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaXRlcl9pby0+Y2FjaGUuaSA9IGl0ZXJf aW8tPmNhY2hlLmVuZDsKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpdGVy X2lvLT5jYWNoZS5lbmQgKz0gc2dfZG1hX2xlbihpdGVyX2lvLQo+ID4gPiA+ID5jYWNoZS5zZykg Pj4KPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg UEFHRV9TSElGVDsKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpdGVyX2lv LT5jYWNoZS5vZmZzID0gc2dfZG1hX2FkZHJlc3MoaXRlcl9pby0KPiA+ID4gPiA+Y2FjaGUuc2cp IC0KPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg aXRlcl9pby0+c3RhcnQ7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCB9Cj4gPiA+ID4gKwo+ID4gPiA+ ICvCoMKgwqDCoMKgwqAgaWYgKGkgPCBpdGVyX2lvLT5jYWNoZS5pKSB7Cj4gPiA+ID4gK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaXRlcl9pby0+Y2FjaGUuZW5kID0gMDsKPiA+ID4gPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpdGVyX2lvLT5jYWNoZS5zZyA9IE5VTEw7Cj4g PiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZ290byByZXRyeTsKPiA+ID4gPiAr wqDCoMKgwqDCoMKgIH0KPiA+ID4gPiArCj4gPiA+ID4gK8KgwqDCoMKgwqDCoCBhZGRyID0gaW9f bWFwcGluZ19tYXBfbG9jYWxfd2MoaXRlcl9pby0+aW9tYXAsIGl0ZXJfaW8tCj4gPiA+ID4gPmNh Y2hlLm9mZnMgKwo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCAoKChyZXNvdXJjZV9zaXplX3Qp aSAtCj4gPiA+ID4gaXRlcl9pby0+Y2FjaGUuaSkKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCA8PCBQQUdFX1NISUZUKSk7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCBkbWFfYnVmX21hcF9zZXRf dmFkZHJfaW9tZW0oZG1hcCwgYWRkcik7Cj4gPiA+ID4gK30KPiA+ID4gPiArCj4gPiA+ID4gK3N0 YXRpYyB2b2lkIHR0bV9rbWFwX2l0ZXJfaW9tYXBfdW5tYXBfbG9jYWwoc3RydWN0Cj4gPiA+ID4g dHRtX2ttYXBfaXRlciAqaXRlciwKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IHN0cnVjdCBkbWFfYnVmX21hcAo+ID4gPiA+ICptYXApCj4gPiA+ID4gK3sKPiA+ID4gPiArwqDC oMKgwqDCoMKgIGlvX21hcHBpbmdfdW5tYXBfbG9jYWwobWFwLT52YWRkcl9pb21lbSk7Cj4gPiA+ ID4gK30KPiA+ID4gPiArCj4gPiA+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgdHRtX2ttYXBfaXRl cl9vcHMgdHRtX2ttYXBfaXRlcl9pb19vcHMgPSB7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoCAubWFw X2xvY2FsID3CoCB0dG1fa21hcF9pdGVyX2lvbWFwX21hcF9sb2NhbCwKPiA+ID4gPiArwqDCoMKg wqDCoMKgIC51bm1hcF9sb2NhbCA9IHR0bV9rbWFwX2l0ZXJfaW9tYXBfdW5tYXBfbG9jYWwsCj4g PiA+ID4gK8KgwqDCoMKgwqDCoCAubWFwc190dCA9IGZhbHNlLAo+ID4gPiA+ICt9Owo+ID4gPiA+ ICsKPiA+ID4gPiArLyoqCj4gPiA+ID4gKyAqIHR0bV9rbWFwX2l0ZXJfaW9tYXBfaW5pdCAtIElu aXRpYWxpemUgYSBzdHJ1Y3QKPiA+ID4gPiB0dG1fa21hcF9pdGVyX2lvbWFwCj4gPiA+ID4gKyAq IEBpdGVyX2lvOiBUaGUgc3RydWN0IHR0bV9rbWFwX2l0ZXJfaW9tYXAgdG8gaW5pdGlhbGl6ZS4K PiA+ID4gPiArICogQGlvbWFwOiBUaGUgc3RydWN0IGlvX21hcHBpbmcgcmVwcmVzZW50aW5nIHRo ZSB1bmRlcmx5aW5nCj4gPiA+ID4gbGluZWFyIGlvX21lbW9yeS4KPiA+ID4gPiArICogQHN0OiBz Z190YWJsZSBpbnRvIEBpb21hcCwgcmVwcmVzZW50aW5nIHRoZSBtZW1vcnkgb2YgdGhlCj4gPiA+ ID4gc3RydWN0Cj4gPiA+ID4gKyAqIHR0bV9yZXNvdXJjZS4KPiA+ID4gPiArICogQHN0YXJ0OiBP ZmZzZXQgdGhhdCBuZWVkcyB0byBiZSBzdWJ0cmFjdGVkIGZyb20gQHN0IHRvIG1ha2UKPiA+ID4g PiArICogc2dfZG1hX2FkZHJlc3Moc3QtPnNnbCkgLSBAc3RhcnQgPT0gMCBmb3IgQGlvbWFwIHN0 YXJ0Lgo+ID4gPiA+ICsgKgo+ID4gPiA+ICsgKiBSZXR1cm46IFBvaW50ZXIgdG8gdGhlIGVtYmVk ZGVkIHN0cnVjdCB0dG1fa21hcF9pdGVyLgo+ID4gPiA+ICsgKi8KPiA+ID4gPiArc3RydWN0IHR0 bV9rbWFwX2l0ZXIgKgo+ID4gPiA+ICt0dG1fa21hcF9pdGVyX2lvbWFwX2luaXQoc3RydWN0IHR0 bV9rbWFwX2l0ZXJfaW9tYXAgKml0ZXJfaW8sCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3RydWN0IGlvX21hcHBpbmcgKmlvbWFwLAo+ID4g PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0cnVj dCBzZ190YWJsZSAqc3QsCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgcmVzb3VyY2Vfc2l6ZV90IHN0YXJ0KQo+ID4gPiA+ICt7Cj4gPiA+ID4g K8KgwqDCoMKgwqDCoCBpdGVyX2lvLT5iYXNlLm9wcyA9ICZ0dG1fa21hcF9pdGVyX2lvX29wczsK PiA+ID4gPiArwqDCoMKgwqDCoMKgIGl0ZXJfaW8tPmlvbWFwID0gaW9tYXA7Cj4gPiA+ID4gK8Kg wqDCoMKgwqDCoCBpdGVyX2lvLT5zdCA9IHN0Owo+ID4gPiA+ICvCoMKgwqDCoMKgwqAgaXRlcl9p by0+c3RhcnQgPSBzdGFydDsKPiA+ID4gPiArwqDCoMKgwqDCoMKgIG1lbXNldCgmaXRlcl9pby0+ Y2FjaGUsIDAsIHNpemVvZihpdGVyX2lvLT5jYWNoZSkpOwo+ID4gPiA+ICsKPiA+ID4gPiArwqDC oMKgwqDCoMKgIHJldHVybiAmaXRlcl9pby0+YmFzZTsKPiA+ID4gPiArfQo+ID4gPiA+ICtFWFBP UlRfU1lNQk9MKHR0bV9rbWFwX2l0ZXJfaW9tYXBfaW5pdCk7Cj4gPiA+ID4gKwo+ID4gPiA+ICsv KioKPiA+ID4gPiArICogRE9DOiBMaW5lYXIgaW8gaXRlcmF0b3IKPiA+ID4gPiArICoKPiA+ID4g PiArICogVGhpcyBjb2RlIHNob3VsZCBkaWUgaW4gdGhlIG5vdCB0b28gbmVhciBmdXR1cmUuIEJl c3Qgd291bGQKPiA+ID4gPiBiZSBpZiB3ZSBjb3VsZAo+ID4gPiA+ICsgKiBtYWtlIGlvLW1hcHBp bmcgdXNlIG1lbXJlbWFwIGZvciBhbGwgaW8gbWVtb3J5LCBhbmQgaGF2ZQo+ID4gPiA+IG1lbXJl bWFwCj4gPiA+ID4gKyAqIGltcGxlbWVudCBhIGttYXBfbG9jYWwgZnVuY3Rpb25hbGl0eS4gV2Ug Y291bGQgdGhlbiBzdHJpcCBhCj4gPiA+ID4gaHVnZSBhbW91bnQgb2YKPiA+ID4gPiArICogY29k ZS4gVGhlc2UgbGluZWFyIGlvIGl0ZXJhdG9ycyBhcmUgaW1wbGVtZW50ZWQgdG8gbWltaWMKPiA+ ID4gPiBvbGQgZnVuY3Rpb25hbGl0eSwKPiA+ID4gPiArICogYW5kIHRoZXkgZG9uJ3QgdXNlIGtt YXBfbG9jYWwgc2VtYW50aWNzIGF0IGFsbCBpbnRlcm5hbGx5Lgo+ID4gPiA+IFJhdGhlciBpb3Jl bWFwIG9yCj4gPiA+ID4gKyAqIGZyaWVuZHMsIGFuZCBhdCBsZWFzdCBvbiAzMi1iaXQgdGhleSBh ZGQgZ2xvYmFsIFRMQiBmbHVzaGVzCj4gPiA+ID4gYW5kIHBvaW50cwo+ID4gPiA+ICsgKiBvZiBm YWlsdXJlLgo+ID4gPiA+ICsgKi8KPiA+ID4gPiArCj4gPiA+ID4gK3N0YXRpYyB2b2lkIHR0bV9r bWFwX2l0ZXJfbGluZWFyX2lvX21hcF9sb2NhbChzdHJ1Y3QKPiA+ID4gPiB0dG1fa21hcF9pdGVy ICppdGVyLAo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN0cnVjdAo+ ID4gPiA+IGRtYV9idWZfbWFwICpkbWFwLAo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIHBnb2ZmX3QgaSkKPiA+ID4gPiArewo+ID4gPiA+ICvCoMKgwqDCoMKgwqAgc3Ry dWN0IHR0bV9rbWFwX2l0ZXJfbGluZWFyX2lvICppdGVyX2lvID0KPiA+ID4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCBjb250YWluZXJfb2YoaXRlciwgdHlwZW9mKCppdGVyX2lvKSwg YmFzZSk7Cj4gPiA+ID4gKwo+ID4gPiA+ICvCoMKgwqDCoMKgwqAgKmRtYXAgPSBpdGVyX2lvLT5k bWFwOwo+ID4gPiA+ICvCoMKgwqDCoMKgwqAgZG1hX2J1Zl9tYXBfaW5jcihkbWFwLCBpICogUEFH RV9TSVpFKTsKPiA+ID4gPiArfQo+ID4gPiA+ICsKPiA+ID4gPiArc3RhdGljIGNvbnN0IHN0cnVj dCB0dG1fa21hcF9pdGVyX29wcwo+ID4gPiA+IHR0bV9rbWFwX2l0ZXJfbGluZWFyX2lvX29wcyA9 IHsKPiA+ID4gPiArwqDCoMKgwqDCoMKgIC5tYXBfbG9jYWwgPcKgIHR0bV9rbWFwX2l0ZXJfbGlu ZWFyX2lvX21hcF9sb2NhbCwKPiA+ID4gPiArwqDCoMKgwqDCoMKgIC5tYXBzX3R0ID0gZmFsc2Us Cj4gPiA+ID4gK307Cj4gPiA+ID4gKwo+ID4gPiA+ICtzdHJ1Y3QgdHRtX2ttYXBfaXRlciAqCj4g PiA+ID4gK3R0bV9rbWFwX2l0ZXJfbGluZWFyX2lvX2luaXQoc3RydWN0IHR0bV9rbWFwX2l0ZXJf bGluZWFyX2lvCj4gPiA+ID4gKml0ZXJfaW8sCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3QgdHRtX2RldmljZSAqYmRl diwKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIHN0cnVjdCB0dG1fcmVzb3VyY2UgKm1lbSkKPiA+ID4gPiArewo+ID4gPiA+ICvC oMKgwqDCoMKgwqAgaW50IHJldDsKPiA+ID4gPiArCj4gPiA+ID4gK8KgwqDCoMKgwqDCoCByZXQg PSB0dG1fbWVtX2lvX3Jlc2VydmUoYmRldiwgbWVtKTsKPiA+ID4gPiArwqDCoMKgwqDCoMKgIGlm IChyZXQpCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZ290byBvdXRfZXJy Owo+ID4gPiA+ICvCoMKgwqDCoMKgwqAgaWYgKCFtZW0tPmJ1cy5pc19pb21lbSkgewo+ID4gPiA+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldCA9IC1FSU5WQUw7Cj4gPiA+ID4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZ290byBvdXRfaW9fZnJlZTsKPiA+ID4gPiArwqDC oMKgwqDCoMKgIH0KPiA+ID4gPiArCj4gPiA+ID4gK8KgwqDCoMKgwqDCoCBpZiAobWVtLT5idXMu YWRkcikgewo+ID4gPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGRtYV9idWZfbWFw X3NldF92YWRkcigmaXRlcl9pby0+ZG1hcCwgbWVtLQo+ID4gPiA+ID5idXMuYWRkcik7Cj4gPiA+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaXRlcl9pby0+bmVlZHNfdW5tYXAgPSBm YWxzZTsKPiA+ID4gPiArwqDCoMKgwqDCoMKgIH0gZWxzZSB7Cj4gPiA+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgc2l6ZV90IGJ1c19zaXplID0gKHNpemVfdCltZW0tPm51bV9wYWdl cyA8PAo+ID4gPiA+IFBBR0VfU0hJRlQ7Cj4gPiA+ID4gKwo+ID4gPiA+ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIGl0ZXJfaW8tPm5lZWRzX3VubWFwID0gdHJ1ZTsKPiA+ID4gPiArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAobWVtLT5idXMuY2FjaGluZyA9PSB0dG1fd3Jp dGVfY29tYmluZWQpCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIGRtYV9idWZfbWFwX3NldF92YWRkcl9pb21lbSgmaXRlcl9pby0KPiA+ID4gPiA+ ZG1hcCwKPiA+ID4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oAo+ID4gPiA+IGlvcmVtYXBfd2MobWVtLT5idXMub2Zmc2V0LAo+ID4gPiA+ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoAo+ ID4gPiA+IGJ1c19zaXplKSk7Cj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg ZWxzZSBpZiAobWVtLT5idXMuY2FjaGluZyA9PSB0dG1fY2FjaGVkKQo+ID4gPiA+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkbWFfYnVmX21hcF9zZXRfdmFk ZHIoJml0ZXJfaW8tPmRtYXAsCj4gPiA+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqAgbWVtcmVtYXAobWVtLQo+ID4gPiA+ID5idXMub2Zmc2V0LCBidXNfc2l6ZSwKPiA+ID4gPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoAo+ID4gPiA+ IE1FTVJFTUFQX1dCKSk7Cj4gPiA+IFRoZSBjb21tZW50cyBpbiBzZXRfdmFkZHIgc3VnZ2VzdCB0 aGF0IHRoaXMgaXMgbWVhbnQgZm9yCj4gPiA+IHN5c3RlbS1tZW1vcnkuIERvZXMgdGhhdCBhY3R1 YWxseSBtYXR0ZXIgb3IgaXMgaXQganVzdCBhYm91dCBub3QKPiA+ID4gbG9zaW5nIHRoZSBfX2lv bWVtIGFubm90YXRpb24gb24gcGxhdGZvcm1zIHdoZXJlIGl0IG1hdHRlcnM/Cj4gPiAKPiA+IFll cywgaXQncyB0aGUgbGF0dGVyLiBkbWFfYnVmX21hcCgpIGlzIHJlbGF0aXZlbHkgbmV3IGFuZCB0 aGUKPiA+IGF1dGhvcgo+ID4gcHJvYmFibHkgZGlkbid0IHRoaW5rIGFib3V0IHRoZSBjYXNlIG9m IGNhY2hlZCBpb21lbSwgd2hpY2ggaXMgdXNlZAo+ID4gYnksCj4gPiBmb3IgZXhhbXBsZSwgdm13 Z2Z4Lgo+ID4gCj4gPiA+IEFwcGFyZW50bHkgY2FjaGVkIGRldmljZSBsb2NhbCBpcyBhIHRoaW5n LiBBbHNvIHNob3VsZCB0aGlzIG5vdAo+ID4gPiBiZQo+ID4gPiB3cmFwcGVkIGluIENPTkZJR19Y ODY/Cj4gPiAKPiA+IEJvdGggZG1hX2J1Zl9tYXAoKSBhbmQgbWVtcmVtYXAgYXJlIGdlbmVyaWMs IEkgdGhpbmssIEkgZ3Vlc3MKPiA+IG1lbXJlbWFwCj4gPiB3b3VsZCByZXR1cm4gTlVMTCBpZiBp dCdzIG5vdCBzdXBwb3J0ZWQuCj4gCj4gSXQgbG9va3MgbGlrZSBtZW1yZW1hcCBqdXN0IHdyYXBz IGlvcmVtYXBfY2FjaGUsIGJ1dCBzaW5jZSBpdCBhbHNvCj4gZGlzY2FyZHMgdGhlIF9faW9tZW0g YW5ub3RhdGlvbiBzaG91bGQgd2UgYmUgZG9pbmcgdGhhdCB1bml2ZXJzYWxseT8KPiBBbHNvIG5v dCBzdXJlIGlmIGlvcmVtYXBfY2FjaGUgaXMgdW5pdmVyc2FsbHkgc3VwcG9ydGVkLCBzbyB3cmFw cGluZwo+IGluIENPTkZJR19YODYgYW5kIGZhbGxpbmcgYmFjayB0byBwbGFpbiBpb3JlbWFwKCkg bWlnaHQgYmUgbmVlZGVkPyBPcgo+IGF0IGxlYXN0IHRoYXQgbG9va3MgbGlrZSByb3VnaGx5IHdo YXQgdGhlIHByZXZpb3VzIGNvZGUgd2FzIGRvaW5nPwo+IE5vdAo+IHRvbyBzdXJlIHRiaC4KPiAK CkkgdGhpbmsgdGhlIGxvbmcgdGVybSBnb2FsIGlzIHRvIHVzZSBtZW1yZW1hcCBhbGwgb3ZlciB0 aGUgcGxhY2UsIHRvCmp1c3Qgbm90IGhhdmUgdG8gYm90aGVyIHdpdGggdGhlIF9faW9tZW0gYW5u b3RhdGlvbi4gQnV0IHRvIGRvIHRoYXQgaW8tCm1hcHBpbmcuaCBuZWVkcyB0byBzdXBwb3J0IG1l bXJlbWFwLiBCdXQgZm9yIG5vdyB3ZSBuZWVkIHRvIGJlIHN0cmljdAphYm91dCBfX2lvbWVtIHVu bGVzcyB3ZSdyZSBpbiBhcmNoIHNwZWNpZmljIGNvZGUuIFRoYXQncyB3aHkgdGhhdApkbWFfYnVm X21hcCB0aGluZyB3YXMgY3JlYXRlZCwgYnV0IFRUTSBtZW1jcHkgd2FzIG5ldmVyIGZ1bGx5IGFk YXB0ZWQuCgpBcyBmb3IgbGltaXRlZCBhcmNoIHN1cHBvcnQgZm9yIG1lbXJlbWFwIGNhY2hlZCwg SXQgbG9va3MgbGlrZSB3ZSBvbmx5Cm5lZWQgdG8gb3IgaW4gImJhY2t1cCIgbWFwcGluZyBtb2Rl cyBpbiB0aGUgbWVtcmVtYXAgZmxhZ3MsIGFuZCB3ZSdkCm1pbWljIHRoZSBwcmV2aW91cyBiZWhh dmlvdXIuCgovVGhvbWFzCgoKPiA+IAo+ID4gL1Rob21hcwo+ID4gCj4gPiAKCgpfX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpJbnRlbC1nZnggbWFpbGluZyBs aXN0CkludGVsLWdmeEBsaXN0cy5mcmVlZGVza3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5mcmVlZGVz a3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9pbnRlbC1nZngK