From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34342) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cnM6Q-0007WR-2R for qemu-devel@nongnu.org; Mon, 13 Mar 2017 05:17:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cnM6L-0004oH-VO for qemu-devel@nongnu.org; Mon, 13 Mar 2017 05:17:18 -0400 Received: from smtp.ctxuk.citrix.com ([185.25.65.24]:3364 helo=SMTP.EU.CITRIX.COM) by eggs.gnu.org with esmtps (TLS1.0:RSA_ARCFOUR_SHA1:16) (Exim 4.71) (envelope-from ) id 1cnM6L-0004l1-J2 for qemu-devel@nongnu.org; Mon, 13 Mar 2017 05:17:13 -0400 From: Paul Durrant Date: Mon, 13 Mar 2017 09:17:08 +0000 Message-ID: <28eabb0e517e46b6b644f11d32d70e3d@AMSPEX02CL03.citrite.net> References: <1489176412-30529-1-git-send-email-igor.druzhinin@citrix.com> In-Reply-To: <1489176412-30529-1-git-send-email-igor.druzhinin@citrix.com> Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [Qemu-devel] [PATCH v2] xen: don't save/restore the physmap on VM save/restore List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Igor Druzhinin , "sstabellini@kernel.org" , Anthony Perard Cc: "qemu-devel@nongnu.org" , "xen-devel@lists.xenproject.org" > -----Original Message----- > From: Igor Druzhinin > Sent: 10 March 2017 20:07 > To: sstabellini@kernel.org; Anthony Perard > Cc: Paul Durrant ; qemu-devel@nongnu.org; xen- > devel@lists.xenproject.org; Igor Druzhinin > Subject: [PATCH v2] xen: don't save/restore the physmap on VM > save/restore >=20 > Saving/restoring the physmap to/from xenstore was introduced to > QEMU majorly in order to cover up the VRAM region restore issue. > The sequence of restore operations implies that we should know > the effective guest VRAM address *before* we have the VRAM region > restored (which happens later). Unfortunately, in Xen environment > VRAM memory does actually belong to a guest - not QEMU itself - > which means the position of this region is unknown beforehand and > can't be mapped into QEMU address space immediately. >=20 > Previously, recreating xenstore keys, holding the physmap, by the > toolstack helped to get this information in place at the right > moment ready to be consumed by QEMU to map the region properly. >=20 > The extraneous complexity of having those keys transferred by the > toolstack and unnecessary redundancy prompted us to propose a > solution which doesn't require any extra data in xenstore. The idea > is to defer the VRAM region mapping till the point we actually know > the effective address and able to map it. To that end, we initially > only register the pointer to the framebuffer without actual mapping. > Then, during the memory region restore phase, we perform the mapping > of the known address and update the VRAM region metadata (including > previously registered pointer) accordingly. >=20 > Signed-off-by: Igor Druzhinin > --- > v2: > * Fix some building and coding style issues > --- > exec.c | 3 ++ > hw/display/vga.c | 2 +- > include/hw/xen/xen.h | 2 +- > xen-hvm-stub.c | 2 +- > xen-hvm.c | 114 ++++++++++++---------------------------------= ------ > 5 files changed, 33 insertions(+), 90 deletions(-) >=20 > diff --git a/exec.c b/exec.c > index aabb035..5f2809e 100644 > --- a/exec.c > +++ b/exec.c > @@ -2008,6 +2008,9 @@ void *qemu_map_ram_ptr(RAMBlock *ram_block, > ram_addr_t addr) > } >=20 > block->host =3D xen_map_cache(block->offset, block->max_length, = 1); > + if (block->host =3D=3D NULL) { > + return NULL; > + } I don't think this is right. Callers of this function do not seem to ever e= xpect it to fail. Specifically the call to memory_region_get_ram_ptr() made= by vga_common_init() just stashes the pointer as the VRAM base and never c= hecks its validity. Anyway, if you modify do this code, you should cc the appropriate maintaine= rs (Guest CPU cores) and justify why you need to. > } > return ramblock_ptr(block, addr); > } > diff --git a/hw/display/vga.c b/hw/display/vga.c > index 69c3e1d..be554c2 100644 > --- a/hw/display/vga.c > +++ b/hw/display/vga.c > @@ -2163,7 +2163,7 @@ void vga_common_init(VGACommonState *s, > Object *obj, bool global_vmstate) > memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size, > &error_fatal); > vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj)); > - xen_register_framebuffer(&s->vram); > + xen_register_framebuffer(&s->vram, &s->vram_ptr); > s->vram_ptr =3D memory_region_get_ram_ptr(&s->vram); > s->get_bpp =3D vga_get_bpp; > s->get_offsets =3D vga_get_offsets; > diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h > index 09c2ce5..3831843 100644 > --- a/include/hw/xen/xen.h > +++ b/include/hw/xen/xen.h > @@ -45,6 +45,6 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t > size, > struct MemoryRegion *mr, Error **errp); > void xen_modified_memory(ram_addr_t start, ram_addr_t length); >=20 > -void xen_register_framebuffer(struct MemoryRegion *mr); > +void xen_register_framebuffer(struct MemoryRegion *mr, uint8_t **ptr); >=20 > #endif /* QEMU_HW_XEN_H */ > diff --git a/xen-hvm-stub.c b/xen-hvm-stub.c > index c500325..c89065e 100644 > --- a/xen-hvm-stub.c > +++ b/xen-hvm-stub.c > @@ -46,7 +46,7 @@ qemu_irq *xen_interrupt_controller_init(void) > return NULL; > } >=20 > -void xen_register_framebuffer(MemoryRegion *mr) > +void xen_register_framebuffer(MemoryRegion *mr, uint8_t **ptr) > { > } >=20 > diff --git a/xen-hvm.c b/xen-hvm.c > index 5043beb..270cd99 100644 > --- a/xen-hvm.c > +++ b/xen-hvm.c > @@ -41,6 +41,7 @@ >=20 > static MemoryRegion ram_memory, ram_640k, ram_lo, ram_hi; > static MemoryRegion *framebuffer; > +static uint8_t **framebuffer_ptr; > static bool xen_in_migration; >=20 > /* Compatibility with older version */ > @@ -302,7 +303,6 @@ static hwaddr xen_phys_offset_to_gaddr(hwaddr > start_addr, > return physmap->start_addr; > } > } > - Pure whitespace fix. Needs to either be called out in the commit comment or= separated. The rest of the patch looks good to me. Paul > return start_addr; > } >=20 > @@ -317,7 +317,6 @@ static int xen_add_to_physmap(XenIOState *state, > XenPhysmap *physmap =3D NULL; > hwaddr pfn, start_gpfn; > hwaddr phys_offset =3D memory_region_get_ram_addr(mr); > - char path[80], value[17]; > const char *mr_name; >=20 > if (get_physmapping(state, start_addr, size)) { > @@ -340,6 +339,27 @@ go_physmap: > DPRINTF("mapping vram to %"HWADDR_PRIx" - %"HWADDR_PRIx"\n", > start_addr, start_addr + size); >=20 > + mr_name =3D memory_region_name(mr); > + > + physmap =3D g_malloc(sizeof(XenPhysmap)); > + > + physmap->start_addr =3D start_addr; > + physmap->size =3D size; > + physmap->name =3D mr_name; > + physmap->phys_offset =3D phys_offset; > + > + QLIST_INSERT_HEAD(&state->physmap, physmap, list); > + > + if (runstate_check(RUN_STATE_INMIGRATE)) { > + /* At this point we have a physmap entry for the framebuffer reg= ion > + * established during the restore phase so we can safely update = the > + * registered framebuffer address here. */ The jump to go_physmap is predicated on (mr =3D=3D framebuffer && start_add= r > 0xbffff) so the following 'if' is unnecessary. > + if (mr =3D=3D framebuffer) { > + *framebuffer_ptr =3D memory_region_get_ram_ptr(framebuffer); > + } > + return 0; > + } > + > pfn =3D phys_offset >> TARGET_PAGE_BITS; > start_gpfn =3D start_addr >> TARGET_PAGE_BITS; > for (i =3D 0; i < size >> TARGET_PAGE_BITS; i++) { > @@ -350,49 +370,17 @@ go_physmap: > if (rc) { > DPRINTF("add_to_physmap MFN %"PRI_xen_pfn" to PFN %" > PRI_xen_pfn" failed: %d (errno: %d)\n", idx, gpfn, r= c, errno); > + > + QLIST_REMOVE(physmap, list); > + g_free(physmap); > return -rc; > } > } >=20 > - mr_name =3D memory_region_name(mr); > - > - physmap =3D g_malloc(sizeof (XenPhysmap)); > - > - physmap->start_addr =3D start_addr; > - physmap->size =3D size; > - physmap->name =3D mr_name; > - physmap->phys_offset =3D phys_offset; > - > - QLIST_INSERT_HEAD(&state->physmap, physmap, list); > - > xc_domain_pin_memory_cacheattr(xen_xc, xen_domid, > start_addr >> TARGET_PAGE_BITS, > (start_addr + size - 1) >> TARGET_PAG= E_BITS, > XEN_DOMCTL_MEM_CACHEATTR_WB); > - > - snprintf(path, sizeof(path), > - "/local/domain/0/device- > model/%d/physmap/%"PRIx64"/start_addr", > - xen_domid, (uint64_t)phys_offset); > - snprintf(value, sizeof(value), "%"PRIx64, (uint64_t)start_addr); > - if (!xs_write(state->xenstore, 0, path, value, strlen(value))) { > - return -1; > - } > - snprintf(path, sizeof(path), > - "/local/domain/0/device-model/%d/physmap/%"PRIx64"/size", > - xen_domid, (uint64_t)phys_offset); > - snprintf(value, sizeof(value), "%"PRIx64, (uint64_t)size); > - if (!xs_write(state->xenstore, 0, path, value, strlen(value))) { > - return -1; > - } > - if (mr_name) { > - snprintf(path, sizeof(path), > - "/local/domain/0/device-model/%d/physmap/%"PRIx64"/name"= , > - xen_domid, (uint64_t)phys_offset); > - if (!xs_write(state->xenstore, 0, path, mr_name, strlen(mr_name)= )) { > - return -1; > - } > - } > - > return 0; > } >=20 > @@ -1152,54 +1140,6 @@ static void xen_exit_notifier(Notifier *n, void > *data) > xs_daemon_close(state->xenstore); > } >=20 > -static void xen_read_physmap(XenIOState *state) > -{ > - XenPhysmap *physmap =3D NULL; > - unsigned int len, num, i; > - char path[80], *value =3D NULL; > - char **entries =3D NULL; > - > - snprintf(path, sizeof(path), > - "/local/domain/0/device-model/%d/physmap", xen_domid); > - entries =3D xs_directory(state->xenstore, 0, path, &num); > - if (entries =3D=3D NULL) > - return; > - > - for (i =3D 0; i < num; i++) { > - physmap =3D g_malloc(sizeof (XenPhysmap)); > - physmap->phys_offset =3D strtoull(entries[i], NULL, 16); > - snprintf(path, sizeof(path), > - "/local/domain/0/device-model/%d/physmap/%s/start_addr", > - xen_domid, entries[i]); > - value =3D xs_read(state->xenstore, 0, path, &len); > - if (value =3D=3D NULL) { > - g_free(physmap); > - continue; > - } > - physmap->start_addr =3D strtoull(value, NULL, 16); > - free(value); > - > - snprintf(path, sizeof(path), > - "/local/domain/0/device-model/%d/physmap/%s/size", > - xen_domid, entries[i]); > - value =3D xs_read(state->xenstore, 0, path, &len); > - if (value =3D=3D NULL) { > - g_free(physmap); > - continue; > - } > - physmap->size =3D strtoull(value, NULL, 16); > - free(value); > - > - snprintf(path, sizeof(path), > - "/local/domain/0/device-model/%d/physmap/%s/name", > - xen_domid, entries[i]); > - physmap->name =3D xs_read(state->xenstore, 0, path, &len); > - > - QLIST_INSERT_HEAD(&state->physmap, physmap, list); > - } > - free(entries); > -} > - > static void xen_wakeup_notifier(Notifier *notifier, void *data) > { > xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, > 0); > @@ -1339,7 +1279,6 @@ void xen_hvm_init(PCMachineState *pcms, > MemoryRegion **ram_memory) > goto err; > } > xen_be_register_common(); > - xen_read_physmap(state); >=20 > /* Disable ACPI build because Xen handles it */ > pcms->acpi_build_enabled =3D false; > @@ -1374,9 +1313,10 @@ void destroy_hvm_domain(bool reboot) > } > } >=20 > -void xen_register_framebuffer(MemoryRegion *mr) > +void xen_register_framebuffer(MemoryRegion *mr, uint8_t **ptr) > { > framebuffer =3D mr; > + framebuffer_ptr =3D ptr; > } >=20 > void xen_shutdown_fatal_error(const char *fmt, ...) > -- > 2.7.4 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Paul Durrant Subject: Re: [PATCH v2] xen: don't save/restore the physmap on VM save/restore Date: Mon, 13 Mar 2017 09:17:08 +0000 Message-ID: <28eabb0e517e46b6b644f11d32d70e3d@AMSPEX02CL03.citrite.net> References: <1489176412-30529-1-git-send-email-igor.druzhinin@citrix.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cnM6J-0007Hj-Ba for xen-devel@lists.xenproject.org; Mon, 13 Mar 2017 09:17:11 +0000 In-Reply-To: <1489176412-30529-1-git-send-email-igor.druzhinin@citrix.com> Content-Language: en-US List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" To: Igor Druzhinin , "sstabellini@kernel.org" , Anthony Perard Cc: "xen-devel@lists.xenproject.org" , "qemu-devel@nongnu.org" List-Id: xen-devel@lists.xenproject.org PiAtLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQo+IEZyb206IElnb3IgRHJ1emhpbmluCj4gU2Vu dDogMTAgTWFyY2ggMjAxNyAyMDowNwo+IFRvOiBzc3RhYmVsbGluaUBrZXJuZWwub3JnOyBBbnRo b255IFBlcmFyZCA8YW50aG9ueS5wZXJhcmRAY2l0cml4LmNvbT4KPiBDYzogUGF1bCBEdXJyYW50 IDxQYXVsLkR1cnJhbnRAY2l0cml4LmNvbT47IHFlbXUtZGV2ZWxAbm9uZ251Lm9yZzsgeGVuLQo+ IGRldmVsQGxpc3RzLnhlbnByb2plY3Qub3JnOyBJZ29yIERydXpoaW5pbiA8aWdvci5kcnV6aGlu aW5AY2l0cml4LmNvbT4KPiBTdWJqZWN0OiBbUEFUQ0ggdjJdIHhlbjogZG9uJ3Qgc2F2ZS9yZXN0 b3JlIHRoZSBwaHlzbWFwIG9uIFZNCj4gc2F2ZS9yZXN0b3JlCj4gCj4gU2F2aW5nL3Jlc3Rvcmlu ZyB0aGUgcGh5c21hcCB0by9mcm9tIHhlbnN0b3JlIHdhcyBpbnRyb2R1Y2VkIHRvCj4gUUVNVSBt YWpvcmx5IGluIG9yZGVyIHRvIGNvdmVyIHVwIHRoZSBWUkFNIHJlZ2lvbiByZXN0b3JlIGlzc3Vl Lgo+IFRoZSBzZXF1ZW5jZSBvZiByZXN0b3JlIG9wZXJhdGlvbnMgaW1wbGllcyB0aGF0IHdlIHNo b3VsZCBrbm93Cj4gdGhlIGVmZmVjdGl2ZSBndWVzdCBWUkFNIGFkZHJlc3MgKmJlZm9yZSogd2Ug aGF2ZSB0aGUgVlJBTSByZWdpb24KPiByZXN0b3JlZCAod2hpY2ggaGFwcGVucyBsYXRlcikuIFVu Zm9ydHVuYXRlbHksIGluIFhlbiBlbnZpcm9ubWVudAo+IFZSQU0gbWVtb3J5IGRvZXMgYWN0dWFs bHkgYmVsb25nIHRvIGEgZ3Vlc3QgLSBub3QgUUVNVSBpdHNlbGYgLQo+IHdoaWNoIG1lYW5zIHRo ZSBwb3NpdGlvbiBvZiB0aGlzIHJlZ2lvbiBpcyB1bmtub3duIGJlZm9yZWhhbmQgYW5kCj4gY2Fu J3QgYmUgbWFwcGVkIGludG8gUUVNVSBhZGRyZXNzIHNwYWNlIGltbWVkaWF0ZWx5Lgo+IAo+IFBy ZXZpb3VzbHksIHJlY3JlYXRpbmcgeGVuc3RvcmUga2V5cywgaG9sZGluZyB0aGUgcGh5c21hcCwg YnkgdGhlCj4gdG9vbHN0YWNrIGhlbHBlZCB0byBnZXQgdGhpcyBpbmZvcm1hdGlvbiBpbiBwbGFj ZSBhdCB0aGUgcmlnaHQKPiBtb21lbnQgcmVhZHkgdG8gYmUgY29uc3VtZWQgYnkgUUVNVSB0byBt YXAgdGhlIHJlZ2lvbiBwcm9wZXJseS4KPiAKPiBUaGUgZXh0cmFuZW91cyBjb21wbGV4aXR5IG9m IGhhdmluZyB0aG9zZSBrZXlzIHRyYW5zZmVycmVkIGJ5IHRoZQo+IHRvb2xzdGFjayBhbmQgdW5u ZWNlc3NhcnkgcmVkdW5kYW5jeSBwcm9tcHRlZCB1cyB0byBwcm9wb3NlIGEKPiBzb2x1dGlvbiB3 aGljaCBkb2Vzbid0IHJlcXVpcmUgYW55IGV4dHJhIGRhdGEgaW4geGVuc3RvcmUuIFRoZSBpZGVh Cj4gaXMgdG8gZGVmZXIgdGhlIFZSQU0gcmVnaW9uIG1hcHBpbmcgdGlsbCB0aGUgcG9pbnQgd2Ug YWN0dWFsbHkga25vdwo+IHRoZSBlZmZlY3RpdmUgYWRkcmVzcyBhbmQgYWJsZSB0byBtYXAgaXQu IFRvIHRoYXQgZW5kLCB3ZSBpbml0aWFsbHkKPiBvbmx5IHJlZ2lzdGVyIHRoZSBwb2ludGVyIHRv IHRoZSBmcmFtZWJ1ZmZlciB3aXRob3V0IGFjdHVhbCBtYXBwaW5nLgo+IFRoZW4sIGR1cmluZyB0 aGUgbWVtb3J5IHJlZ2lvbiByZXN0b3JlIHBoYXNlLCB3ZSBwZXJmb3JtIHRoZSBtYXBwaW5nCj4g b2YgdGhlIGtub3duIGFkZHJlc3MgYW5kIHVwZGF0ZSB0aGUgVlJBTSByZWdpb24gbWV0YWRhdGEg KGluY2x1ZGluZwo+IHByZXZpb3VzbHkgcmVnaXN0ZXJlZCBwb2ludGVyKSBhY2NvcmRpbmdseS4K PiAKPiBTaWduZWQtb2ZmLWJ5OiBJZ29yIERydXpoaW5pbiA8aWdvci5kcnV6aGluaW5AY2l0cml4 LmNvbT4KPiAtLS0KPiB2MjoKPiAqIEZpeCBzb21lIGJ1aWxkaW5nIGFuZCBjb2Rpbmcgc3R5bGUg aXNzdWVzCj4gLS0tCj4gIGV4ZWMuYyAgICAgICAgICAgICAgIHwgICAzICsrCj4gIGh3L2Rpc3Bs YXkvdmdhLmMgICAgIHwgICAyICstCj4gIGluY2x1ZGUvaHcveGVuL3hlbi5oIHwgICAyICstCj4g IHhlbi1odm0tc3R1Yi5jICAgICAgIHwgICAyICstCj4gIHhlbi1odm0uYyAgICAgICAgICAgIHwg MTE0ICsrKysrKysrKysrKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQo+ ICA1IGZpbGVzIGNoYW5nZWQsIDMzIGluc2VydGlvbnMoKyksIDkwIGRlbGV0aW9ucygtKQo+IAo+ IGRpZmYgLS1naXQgYS9leGVjLmMgYi9leGVjLmMKPiBpbmRleCBhYWJiMDM1Li41ZjI4MDllIDEw MDY0NAo+IC0tLSBhL2V4ZWMuYwo+ICsrKyBiL2V4ZWMuYwo+IEBAIC0yMDA4LDYgKzIwMDgsOSBA QCB2b2lkICpxZW11X21hcF9yYW1fcHRyKFJBTUJsb2NrICpyYW1fYmxvY2ssCj4gcmFtX2FkZHJf dCBhZGRyKQo+ICAgICAgICAgIH0KPiAKPiAgICAgICAgICBibG9jay0+aG9zdCA9IHhlbl9tYXBf Y2FjaGUoYmxvY2stPm9mZnNldCwgYmxvY2stPm1heF9sZW5ndGgsIDEpOwo+ICsgICAgICAgIGlm IChibG9jay0+aG9zdCA9PSBOVUxMKSB7Cj4gKyAgICAgICAgICAgIHJldHVybiBOVUxMOwo+ICsg ICAgICAgIH0KCkkgZG9uJ3QgdGhpbmsgdGhpcyBpcyByaWdodC4gQ2FsbGVycyBvZiB0aGlzIGZ1 bmN0aW9uIGRvIG5vdCBzZWVtIHRvIGV2ZXIgZXhwZWN0IGl0IHRvIGZhaWwuIFNwZWNpZmljYWxs eSB0aGUgY2FsbCB0byBtZW1vcnlfcmVnaW9uX2dldF9yYW1fcHRyKCkgbWFkZSBieSB2Z2FfY29t bW9uX2luaXQoKSBqdXN0IHN0YXNoZXMgdGhlIHBvaW50ZXIgYXMgdGhlIFZSQU0gYmFzZSBhbmQg bmV2ZXIgY2hlY2tzIGl0cyB2YWxpZGl0eS4KCkFueXdheSwgaWYgeW91IG1vZGlmeSBkbyB0aGlz IGNvZGUsIHlvdSBzaG91bGQgY2MgdGhlIGFwcHJvcHJpYXRlIG1haW50YWluZXJzIChHdWVzdCBD UFUgY29yZXMpIGFuZCBqdXN0aWZ5IHdoeSB5b3UgbmVlZCB0by4KCj4gICAgICB9Cj4gICAgICBy ZXR1cm4gcmFtYmxvY2tfcHRyKGJsb2NrLCBhZGRyKTsKPiAgfQo+IGRpZmYgLS1naXQgYS9ody9k aXNwbGF5L3ZnYS5jIGIvaHcvZGlzcGxheS92Z2EuYwo+IGluZGV4IDY5YzNlMWQuLmJlNTU0YzIg MTAwNjQ0Cj4gLS0tIGEvaHcvZGlzcGxheS92Z2EuYwo+ICsrKyBiL2h3L2Rpc3BsYXkvdmdhLmMK PiBAQCAtMjE2Myw3ICsyMTYzLDcgQEAgdm9pZCB2Z2FfY29tbW9uX2luaXQoVkdBQ29tbW9uU3Rh dGUgKnMsCj4gT2JqZWN0ICpvYmosIGJvb2wgZ2xvYmFsX3Ztc3RhdGUpCj4gICAgICBtZW1vcnlf cmVnaW9uX2luaXRfcmFtKCZzLT52cmFtLCBvYmosICJ2Z2EudnJhbSIsIHMtPnZyYW1fc2l6ZSwK PiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJmVycm9yX2ZhdGFsKTsKPiAgICAgIHZtc3Rh dGVfcmVnaXN0ZXJfcmFtKCZzLT52cmFtLCBnbG9iYWxfdm1zdGF0ZSA/IE5VTEwgOiBERVZJQ0Uo b2JqKSk7Cj4gLSAgICB4ZW5fcmVnaXN0ZXJfZnJhbWVidWZmZXIoJnMtPnZyYW0pOwo+ICsgICAg eGVuX3JlZ2lzdGVyX2ZyYW1lYnVmZmVyKCZzLT52cmFtLCAmcy0+dnJhbV9wdHIpOwo+ICAgICAg cy0+dnJhbV9wdHIgPSBtZW1vcnlfcmVnaW9uX2dldF9yYW1fcHRyKCZzLT52cmFtKTsKPiAgICAg IHMtPmdldF9icHAgPSB2Z2FfZ2V0X2JwcDsKPiAgICAgIHMtPmdldF9vZmZzZXRzID0gdmdhX2dl dF9vZmZzZXRzOwo+IGRpZmYgLS1naXQgYS9pbmNsdWRlL2h3L3hlbi94ZW4uaCBiL2luY2x1ZGUv aHcveGVuL3hlbi5oCj4gaW5kZXggMDljMmNlNS4uMzgzMTg0MyAxMDA2NDQKPiAtLS0gYS9pbmNs dWRlL2h3L3hlbi94ZW4uaAo+ICsrKyBiL2luY2x1ZGUvaHcveGVuL3hlbi5oCj4gQEAgLTQ1LDYg KzQ1LDYgQEAgdm9pZCB4ZW5fcmFtX2FsbG9jKHJhbV9hZGRyX3QgcmFtX2FkZHIsIHJhbV9hZGRy X3QKPiBzaXplLAo+ICAgICAgICAgICAgICAgICAgICAgc3RydWN0IE1lbW9yeVJlZ2lvbiAqbXIs IEVycm9yICoqZXJycCk7Cj4gIHZvaWQgeGVuX21vZGlmaWVkX21lbW9yeShyYW1fYWRkcl90IHN0 YXJ0LCByYW1fYWRkcl90IGxlbmd0aCk7Cj4gCj4gLXZvaWQgeGVuX3JlZ2lzdGVyX2ZyYW1lYnVm ZmVyKHN0cnVjdCBNZW1vcnlSZWdpb24gKm1yKTsKPiArdm9pZCB4ZW5fcmVnaXN0ZXJfZnJhbWVi dWZmZXIoc3RydWN0IE1lbW9yeVJlZ2lvbiAqbXIsIHVpbnQ4X3QgKipwdHIpOwo+IAo+ICAjZW5k aWYgLyogUUVNVV9IV19YRU5fSCAqLwo+IGRpZmYgLS1naXQgYS94ZW4taHZtLXN0dWIuYyBiL3hl bi1odm0tc3R1Yi5jCj4gaW5kZXggYzUwMDMyNS4uYzg5MDY1ZSAxMDA2NDQKPiAtLS0gYS94ZW4t aHZtLXN0dWIuYwo+ICsrKyBiL3hlbi1odm0tc3R1Yi5jCj4gQEAgLTQ2LDcgKzQ2LDcgQEAgcWVt dV9pcnEgKnhlbl9pbnRlcnJ1cHRfY29udHJvbGxlcl9pbml0KHZvaWQpCj4gICAgICByZXR1cm4g TlVMTDsKPiAgfQo+IAo+IC12b2lkIHhlbl9yZWdpc3Rlcl9mcmFtZWJ1ZmZlcihNZW1vcnlSZWdp b24gKm1yKQo+ICt2b2lkIHhlbl9yZWdpc3Rlcl9mcmFtZWJ1ZmZlcihNZW1vcnlSZWdpb24gKm1y LCB1aW50OF90ICoqcHRyKQo+ICB7Cj4gIH0KPiAKPiBkaWZmIC0tZ2l0IGEveGVuLWh2bS5jIGIv eGVuLWh2bS5jCj4gaW5kZXggNTA0M2JlYi4uMjcwY2Q5OSAxMDA2NDQKPiAtLS0gYS94ZW4taHZt LmMKPiArKysgYi94ZW4taHZtLmMKPiBAQCAtNDEsNiArNDEsNyBAQAo+IAo+ICBzdGF0aWMgTWVt b3J5UmVnaW9uIHJhbV9tZW1vcnksIHJhbV82NDBrLCByYW1fbG8sIHJhbV9oaTsKPiAgc3RhdGlj IE1lbW9yeVJlZ2lvbiAqZnJhbWVidWZmZXI7Cj4gK3N0YXRpYyB1aW50OF90ICoqZnJhbWVidWZm ZXJfcHRyOwo+ICBzdGF0aWMgYm9vbCB4ZW5faW5fbWlncmF0aW9uOwo+IAo+ICAvKiBDb21wYXRp YmlsaXR5IHdpdGggb2xkZXIgdmVyc2lvbiAqLwo+IEBAIC0zMDIsNyArMzAzLDYgQEAgc3RhdGlj IGh3YWRkciB4ZW5fcGh5c19vZmZzZXRfdG9fZ2FkZHIoaHdhZGRyCj4gc3RhcnRfYWRkciwKPiAg ICAgICAgICAgICAgcmV0dXJuIHBoeXNtYXAtPnN0YXJ0X2FkZHI7Cj4gICAgICAgICAgfQo+ICAg ICAgfQo+IC0KClB1cmUgd2hpdGVzcGFjZSBmaXguIE5lZWRzIHRvIGVpdGhlciBiZSBjYWxsZWQg b3V0IGluIHRoZSBjb21taXQgY29tbWVudCBvciBzZXBhcmF0ZWQuClRoZSByZXN0IG9mIHRoZSBw YXRjaCBsb29rcyBnb29kIHRvIG1lLgoKICBQYXVsCgo+ICAgICAgcmV0dXJuIHN0YXJ0X2FkZHI7 Cj4gIH0KPiAKPiBAQCAtMzE3LDcgKzMxNyw2IEBAIHN0YXRpYyBpbnQgeGVuX2FkZF90b19waHlz bWFwKFhlbklPU3RhdGUgKnN0YXRlLAo+ICAgICAgWGVuUGh5c21hcCAqcGh5c21hcCA9IE5VTEw7 Cj4gICAgICBod2FkZHIgcGZuLCBzdGFydF9ncGZuOwo+ICAgICAgaHdhZGRyIHBoeXNfb2Zmc2V0 ID0gbWVtb3J5X3JlZ2lvbl9nZXRfcmFtX2FkZHIobXIpOwo+IC0gICAgY2hhciBwYXRoWzgwXSwg dmFsdWVbMTddOwo+ICAgICAgY29uc3QgY2hhciAqbXJfbmFtZTsKPiAKPiAgICAgIGlmIChnZXRf cGh5c21hcHBpbmcoc3RhdGUsIHN0YXJ0X2FkZHIsIHNpemUpKSB7Cj4gQEAgLTM0MCw2ICszMzks MjcgQEAgZ29fcGh5c21hcDoKPiAgICAgIERQUklOVEYoIm1hcHBpbmcgdnJhbSB0byAlIkhXQURE Ul9QUkl4IiAtICUiSFdBRERSX1BSSXgiXG4iLAo+ICAgICAgICAgICAgICBzdGFydF9hZGRyLCBz dGFydF9hZGRyICsgc2l6ZSk7Cj4gCj4gKyAgICBtcl9uYW1lID0gbWVtb3J5X3JlZ2lvbl9uYW1l KG1yKTsKPiArCj4gKyAgICBwaHlzbWFwID0gZ19tYWxsb2Moc2l6ZW9mKFhlblBoeXNtYXApKTsK PiArCj4gKyAgICBwaHlzbWFwLT5zdGFydF9hZGRyID0gc3RhcnRfYWRkcjsKPiArICAgIHBoeXNt YXAtPnNpemUgPSBzaXplOwo+ICsgICAgcGh5c21hcC0+bmFtZSA9IG1yX25hbWU7Cj4gKyAgICBw aHlzbWFwLT5waHlzX29mZnNldCA9IHBoeXNfb2Zmc2V0Owo+ICsKPiArICAgIFFMSVNUX0lOU0VS VF9IRUFEKCZzdGF0ZS0+cGh5c21hcCwgcGh5c21hcCwgbGlzdCk7Cj4gKwo+ICsgICAgaWYgKHJ1 bnN0YXRlX2NoZWNrKFJVTl9TVEFURV9JTk1JR1JBVEUpKSB7Cj4gKyAgICAgICAgLyogQXQgdGhp cyBwb2ludCB3ZSBoYXZlIGEgcGh5c21hcCBlbnRyeSBmb3IgdGhlIGZyYW1lYnVmZmVyIHJlZ2lv bgo+ICsgICAgICAgICAqIGVzdGFibGlzaGVkIGR1cmluZyB0aGUgcmVzdG9yZSBwaGFzZSBzbyB3 ZSBjYW4gc2FmZWx5IHVwZGF0ZSB0aGUKPiArICAgICAgICAgKiByZWdpc3RlcmVkIGZyYW1lYnVm ZmVyIGFkZHJlc3MgaGVyZS4gKi8KClRoZSBqdW1wIHRvIGdvX3BoeXNtYXAgaXMgcHJlZGljYXRl ZCBvbiAobXIgPT0gZnJhbWVidWZmZXIgJiYgc3RhcnRfYWRkciA+IDB4YmZmZmYpIHNvIHRoZSBm b2xsb3dpbmcgJ2lmJyBpcyB1bm5lY2Vzc2FyeS4KCj4gKyAgICAgICAgaWYgKG1yID09IGZyYW1l YnVmZmVyKSB7Cj4gKyAgICAgICAgICAgICpmcmFtZWJ1ZmZlcl9wdHIgPSBtZW1vcnlfcmVnaW9u X2dldF9yYW1fcHRyKGZyYW1lYnVmZmVyKTsKPiArICAgICAgICB9Cj4gKyAgICAgICAgcmV0dXJu IDA7Cj4gKyAgICB9Cj4gKwo+ICAgICAgcGZuID0gcGh5c19vZmZzZXQgPj4gVEFSR0VUX1BBR0Vf QklUUzsKPiAgICAgIHN0YXJ0X2dwZm4gPSBzdGFydF9hZGRyID4+IFRBUkdFVF9QQUdFX0JJVFM7 Cj4gICAgICBmb3IgKGkgPSAwOyBpIDwgc2l6ZSA+PiBUQVJHRVRfUEFHRV9CSVRTOyBpKyspIHsK PiBAQCAtMzUwLDQ5ICszNzAsMTcgQEAgZ29fcGh5c21hcDoKPiAgICAgICAgICBpZiAocmMpIHsK PiAgICAgICAgICAgICAgRFBSSU5URigiYWRkX3RvX3BoeXNtYXAgTUZOICUiUFJJX3hlbl9wZm4i IHRvIFBGTiAlIgo+ICAgICAgICAgICAgICAgICAgICAgIFBSSV94ZW5fcGZuIiBmYWlsZWQ6ICVk IChlcnJubzogJWQpXG4iLCBpZHgsIGdwZm4sIHJjLCBlcnJubyk7Cj4gKwo+ICsgICAgICAgICAg ICBRTElTVF9SRU1PVkUocGh5c21hcCwgbGlzdCk7Cj4gKyAgICAgICAgICAgIGdfZnJlZShwaHlz bWFwKTsKPiAgICAgICAgICAgICAgcmV0dXJuIC1yYzsKPiAgICAgICAgICB9Cj4gICAgICB9Cj4g Cj4gLSAgICBtcl9uYW1lID0gbWVtb3J5X3JlZ2lvbl9uYW1lKG1yKTsKPiAtCj4gLSAgICBwaHlz bWFwID0gZ19tYWxsb2Moc2l6ZW9mIChYZW5QaHlzbWFwKSk7Cj4gLQo+IC0gICAgcGh5c21hcC0+ c3RhcnRfYWRkciA9IHN0YXJ0X2FkZHI7Cj4gLSAgICBwaHlzbWFwLT5zaXplID0gc2l6ZTsKPiAt ICAgIHBoeXNtYXAtPm5hbWUgPSBtcl9uYW1lOwo+IC0gICAgcGh5c21hcC0+cGh5c19vZmZzZXQg PSBwaHlzX29mZnNldDsKPiAtCj4gLSAgICBRTElTVF9JTlNFUlRfSEVBRCgmc3RhdGUtPnBoeXNt YXAsIHBoeXNtYXAsIGxpc3QpOwo+IC0KPiAgICAgIHhjX2RvbWFpbl9waW5fbWVtb3J5X2NhY2hl YXR0cih4ZW5feGMsIHhlbl9kb21pZCwKPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICBzdGFydF9hZGRyID4+IFRBUkdFVF9QQUdFX0JJVFMsCj4gICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgKHN0YXJ0X2FkZHIgKyBzaXplIC0gMSkgPj4gVEFSR0VUX1BBR0Vf QklUUywKPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBYRU5fRE9NQ1RMX01F TV9DQUNIRUFUVFJfV0IpOwo+IC0KPiAtICAgIHNucHJpbnRmKHBhdGgsIHNpemVvZihwYXRoKSwK PiAtICAgICAgICAgICAgIi9sb2NhbC9kb21haW4vMC9kZXZpY2UtCj4gbW9kZWwvJWQvcGh5c21h cC8lIlBSSXg2NCIvc3RhcnRfYWRkciIsCj4gLSAgICAgICAgICAgIHhlbl9kb21pZCwgKHVpbnQ2 NF90KXBoeXNfb2Zmc2V0KTsKPiAtICAgIHNucHJpbnRmKHZhbHVlLCBzaXplb2YodmFsdWUpLCAi JSJQUkl4NjQsICh1aW50NjRfdClzdGFydF9hZGRyKTsKPiAtICAgIGlmICgheHNfd3JpdGUoc3Rh dGUtPnhlbnN0b3JlLCAwLCBwYXRoLCB2YWx1ZSwgc3RybGVuKHZhbHVlKSkpIHsKPiAtICAgICAg ICByZXR1cm4gLTE7Cj4gLSAgICB9Cj4gLSAgICBzbnByaW50ZihwYXRoLCBzaXplb2YocGF0aCks Cj4gLSAgICAgICAgICAgICIvbG9jYWwvZG9tYWluLzAvZGV2aWNlLW1vZGVsLyVkL3BoeXNtYXAv JSJQUkl4NjQiL3NpemUiLAo+IC0gICAgICAgICAgICB4ZW5fZG9taWQsICh1aW50NjRfdClwaHlz X29mZnNldCk7Cj4gLSAgICBzbnByaW50Zih2YWx1ZSwgc2l6ZW9mKHZhbHVlKSwgIiUiUFJJeDY0 LCAodWludDY0X3Qpc2l6ZSk7Cj4gLSAgICBpZiAoIXhzX3dyaXRlKHN0YXRlLT54ZW5zdG9yZSwg MCwgcGF0aCwgdmFsdWUsIHN0cmxlbih2YWx1ZSkpKSB7Cj4gLSAgICAgICAgcmV0dXJuIC0xOwo+ IC0gICAgfQo+IC0gICAgaWYgKG1yX25hbWUpIHsKPiAtICAgICAgICBzbnByaW50ZihwYXRoLCBz aXplb2YocGF0aCksCj4gLSAgICAgICAgICAgICAgICAiL2xvY2FsL2RvbWFpbi8wL2RldmljZS1t b2RlbC8lZC9waHlzbWFwLyUiUFJJeDY0Ii9uYW1lIiwKPiAtICAgICAgICAgICAgICAgIHhlbl9k b21pZCwgKHVpbnQ2NF90KXBoeXNfb2Zmc2V0KTsKPiAtICAgICAgICBpZiAoIXhzX3dyaXRlKHN0 YXRlLT54ZW5zdG9yZSwgMCwgcGF0aCwgbXJfbmFtZSwgc3RybGVuKG1yX25hbWUpKSkgewo+IC0g ICAgICAgICAgICByZXR1cm4gLTE7Cj4gLSAgICAgICAgfQo+IC0gICAgfQo+IC0KPiAgICAgIHJl dHVybiAwOwo+ICB9Cj4gCj4gQEAgLTExNTIsNTQgKzExNDAsNiBAQCBzdGF0aWMgdm9pZCB4ZW5f ZXhpdF9ub3RpZmllcihOb3RpZmllciAqbiwgdm9pZAo+ICpkYXRhKQo+ICAgICAgeHNfZGFlbW9u X2Nsb3NlKHN0YXRlLT54ZW5zdG9yZSk7Cj4gIH0KPiAKPiAtc3RhdGljIHZvaWQgeGVuX3JlYWRf cGh5c21hcChYZW5JT1N0YXRlICpzdGF0ZSkKPiAtewo+IC0gICAgWGVuUGh5c21hcCAqcGh5c21h cCA9IE5VTEw7Cj4gLSAgICB1bnNpZ25lZCBpbnQgbGVuLCBudW0sIGk7Cj4gLSAgICBjaGFyIHBh dGhbODBdLCAqdmFsdWUgPSBOVUxMOwo+IC0gICAgY2hhciAqKmVudHJpZXMgPSBOVUxMOwo+IC0K PiAtICAgIHNucHJpbnRmKHBhdGgsIHNpemVvZihwYXRoKSwKPiAtICAgICAgICAgICAgIi9sb2Nh bC9kb21haW4vMC9kZXZpY2UtbW9kZWwvJWQvcGh5c21hcCIsIHhlbl9kb21pZCk7Cj4gLSAgICBl bnRyaWVzID0geHNfZGlyZWN0b3J5KHN0YXRlLT54ZW5zdG9yZSwgMCwgcGF0aCwgJm51bSk7Cj4g LSAgICBpZiAoZW50cmllcyA9PSBOVUxMKQo+IC0gICAgICAgIHJldHVybjsKPiAtCj4gLSAgICBm b3IgKGkgPSAwOyBpIDwgbnVtOyBpKyspIHsKPiAtICAgICAgICBwaHlzbWFwID0gZ19tYWxsb2Mo c2l6ZW9mIChYZW5QaHlzbWFwKSk7Cj4gLSAgICAgICAgcGh5c21hcC0+cGh5c19vZmZzZXQgPSBz dHJ0b3VsbChlbnRyaWVzW2ldLCBOVUxMLCAxNik7Cj4gLSAgICAgICAgc25wcmludGYocGF0aCwg c2l6ZW9mKHBhdGgpLAo+IC0gICAgICAgICAgICAgICAgIi9sb2NhbC9kb21haW4vMC9kZXZpY2Ut bW9kZWwvJWQvcGh5c21hcC8lcy9zdGFydF9hZGRyIiwKPiAtICAgICAgICAgICAgICAgIHhlbl9k b21pZCwgZW50cmllc1tpXSk7Cj4gLSAgICAgICAgdmFsdWUgPSB4c19yZWFkKHN0YXRlLT54ZW5z dG9yZSwgMCwgcGF0aCwgJmxlbik7Cj4gLSAgICAgICAgaWYgKHZhbHVlID09IE5VTEwpIHsKPiAt ICAgICAgICAgICAgZ19mcmVlKHBoeXNtYXApOwo+IC0gICAgICAgICAgICBjb250aW51ZTsKPiAt ICAgICAgICB9Cj4gLSAgICAgICAgcGh5c21hcC0+c3RhcnRfYWRkciA9IHN0cnRvdWxsKHZhbHVl LCBOVUxMLCAxNik7Cj4gLSAgICAgICAgZnJlZSh2YWx1ZSk7Cj4gLQo+IC0gICAgICAgIHNucHJp bnRmKHBhdGgsIHNpemVvZihwYXRoKSwKPiAtICAgICAgICAgICAgICAgICIvbG9jYWwvZG9tYWlu LzAvZGV2aWNlLW1vZGVsLyVkL3BoeXNtYXAvJXMvc2l6ZSIsCj4gLSAgICAgICAgICAgICAgICB4 ZW5fZG9taWQsIGVudHJpZXNbaV0pOwo+IC0gICAgICAgIHZhbHVlID0geHNfcmVhZChzdGF0ZS0+ eGVuc3RvcmUsIDAsIHBhdGgsICZsZW4pOwo+IC0gICAgICAgIGlmICh2YWx1ZSA9PSBOVUxMKSB7 Cj4gLSAgICAgICAgICAgIGdfZnJlZShwaHlzbWFwKTsKPiAtICAgICAgICAgICAgY29udGludWU7 Cj4gLSAgICAgICAgfQo+IC0gICAgICAgIHBoeXNtYXAtPnNpemUgPSBzdHJ0b3VsbCh2YWx1ZSwg TlVMTCwgMTYpOwo+IC0gICAgICAgIGZyZWUodmFsdWUpOwo+IC0KPiAtICAgICAgICBzbnByaW50 ZihwYXRoLCBzaXplb2YocGF0aCksCj4gLSAgICAgICAgICAgICAgICAiL2xvY2FsL2RvbWFpbi8w L2RldmljZS1tb2RlbC8lZC9waHlzbWFwLyVzL25hbWUiLAo+IC0gICAgICAgICAgICAgICAgeGVu X2RvbWlkLCBlbnRyaWVzW2ldKTsKPiAtICAgICAgICBwaHlzbWFwLT5uYW1lID0geHNfcmVhZChz dGF0ZS0+eGVuc3RvcmUsIDAsIHBhdGgsICZsZW4pOwo+IC0KPiAtICAgICAgICBRTElTVF9JTlNF UlRfSEVBRCgmc3RhdGUtPnBoeXNtYXAsIHBoeXNtYXAsIGxpc3QpOwo+IC0gICAgfQo+IC0gICAg ZnJlZShlbnRyaWVzKTsKPiAtfQo+IC0KPiAgc3RhdGljIHZvaWQgeGVuX3dha2V1cF9ub3RpZmll cihOb3RpZmllciAqbm90aWZpZXIsIHZvaWQgKmRhdGEpCj4gIHsKPiAgICAgIHhjX3NldF9odm1f cGFyYW0oeGVuX3hjLCB4ZW5fZG9taWQsIEhWTV9QQVJBTV9BQ1BJX1NfU1RBVEUsCj4gMCk7Cj4g QEAgLTEzMzksNyArMTI3OSw2IEBAIHZvaWQgeGVuX2h2bV9pbml0KFBDTWFjaGluZVN0YXRlICpw Y21zLAo+IE1lbW9yeVJlZ2lvbiAqKnJhbV9tZW1vcnkpCj4gICAgICAgICAgZ290byBlcnI7Cj4g ICAgICB9Cj4gICAgICB4ZW5fYmVfcmVnaXN0ZXJfY29tbW9uKCk7Cj4gLSAgICB4ZW5fcmVhZF9w aHlzbWFwKHN0YXRlKTsKPiAKPiAgICAgIC8qIERpc2FibGUgQUNQSSBidWlsZCBiZWNhdXNlIFhl biBoYW5kbGVzIGl0ICovCj4gICAgICBwY21zLT5hY3BpX2J1aWxkX2VuYWJsZWQgPSBmYWxzZTsK PiBAQCAtMTM3NCw5ICsxMzEzLDEwIEBAIHZvaWQgZGVzdHJveV9odm1fZG9tYWluKGJvb2wgcmVi b290KQo+ICAgICAgfQo+ICB9Cj4gCj4gLXZvaWQgeGVuX3JlZ2lzdGVyX2ZyYW1lYnVmZmVyKE1l bW9yeVJlZ2lvbiAqbXIpCj4gK3ZvaWQgeGVuX3JlZ2lzdGVyX2ZyYW1lYnVmZmVyKE1lbW9yeVJl Z2lvbiAqbXIsIHVpbnQ4X3QgKipwdHIpCj4gIHsKPiAgICAgIGZyYW1lYnVmZmVyID0gbXI7Cj4g KyAgICBmcmFtZWJ1ZmZlcl9wdHIgPSBwdHI7Cj4gIH0KPiAKPiAgdm9pZCB4ZW5fc2h1dGRvd25f ZmF0YWxfZXJyb3IoY29uc3QgY2hhciAqZm10LCAuLi4pCj4gLS0KPiAyLjcuNAoKCl9fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fClhlbi1kZXZlbCBtYWlsaW5n IGxpc3QKWGVuLWRldmVsQGxpc3RzLnhlbi5vcmcKaHR0cHM6Ly9saXN0cy54ZW4ub3JnL3hlbi1k ZXZlbAo=