From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Woodhouse Subject: Re: [PATCH 6/9] drm/i915: driver based PASID handling Date: Fri, 09 Oct 2015 08:24:32 +0100 Message-ID: <1444375472.92154.55.camel@infradead.org> References: <1441385943-11508-1-git-send-email-jbarnes@virtuousgeek.org> <1441385943-11508-7-git-send-email-jbarnes@virtuousgeek.org> <20151008155710.GU27939@nuc-i3427.alporthouse.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0117993118==" Return-path: Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) by gabe.freedesktop.org (Postfix) with ESMTPS id BEF866E580 for ; Fri, 9 Oct 2015 00:24:49 -0700 (PDT) In-Reply-To: <20151008155710.GU27939@nuc-i3427.alporthouse.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" To: Chris Wilson , Jesse Barnes Cc: intel-gfx@lists.freedesktop.org List-Id: intel-gfx@lists.freedesktop.org --===============0117993118== Content-Type: multipart/signed; micalg="sha-1"; protocol="application/x-pkcs7-signature"; boundary="=-pgqSgXbpmTOEpAzoyEsZ" --=-pgqSgXbpmTOEpAzoyEsZ Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Thu, 2015-10-08 at 16:57 +0100, Chris Wilson wrote: > Correct me if I am wrong, but it looks like i915_svm implements the > lowlevel interface with the hardware, so by convention is intel_svm.c I think the plan is to drop the driver-mode interface altogether and use the OS-mode version that I posted a few hours ago. So some of your review may not apply; other parts might. > > + struct task_struct *tsk; >=20 > One task? A context can be passed by the device fd to another process. > Do we inherit the VM along with the context? I don't anything to prevent > such. You still get to deal with this, and yes =E2=80=94 the assigned PASID value (given by the intel_svm_bind_mm() call) will continue to refer to the VM of the process which called intel_svm_bind_mm(). Even when it's used from elsewhere. Note that you *could* bind the PASID at the time you actually submit the request, and in that case you could bind it to the VM of the process which is submitting the request, rather than the process which did the initial setup. > > +static void gpu_mm_segv(struct task_struct *tsk, unsigned long > > address, > > + int si_code) > > +{ > > + siginfo_t info; > > + > > + /* Need specific signal info here */ > > + info.si_signo =3D SIGSEGV; > > + info.si_errno =3D EIO; > > + info.si_code =3D si_code; > > + info.si_addr =3D (void __user *)address; > > + > > + force_sig_info(SIGSEGV, &info, tsk); >=20 > force_sig_info() is not exported, ah you builtin i915-svm.c I'm leaving this with you too, as discussed in a separate thread. The OS-mode IOMMU support is just returning an appropriate 'failed' response code to the page request, and letting the endpoint device handle that as it sees fit. > > + spin_lock(&dev_priv->svm.lock); > > + ctx =3D dev_priv->svm.pasid_ctx[desc.pasid]; > > + tsk =3D ctx->tsk; > > + mm =3D tsk->mm; > > + address =3D desc.addr << PAGE_SHIFT; > > + ringbuf =3D ctx->engine[RCS].ringbuf; > > + spin_unlock(&dev_priv->svm.lock); >=20 > All of the above can disappear at anytime after the unlock? Answering for my own code... I don't touch any of the gfx context stuff, obviously, and I don't even use the task. I do have a reference on the mm and it isn't going away. > > + > > + down_read_trylock(&mm->mmap_sem); > > + vma =3D find_extend_vma(mm, address); > > + if (!vma || address < vma->vm_start) { > > + DRM_ERROR("bad VMA or address out of range\n"); Um... Jesse, I used that same 'address < vma->vm_start' check in my own version. But is that going to prevent us from allowing the GPU to grow the stack VMA downwards? I note the AMD one does it too. > > +/* Make sure GPU writes can't hit the mm that's about to go away > > */ > > +static void intel_mm_release(struct mmu_notifier *mn, struct > > mm_struct *mm) > > +{ > > + struct intel_mm_struct *ims =3D container_of(mn, struct > > intel_mm_struct, > > + notifier); > > + struct drm_i915_private *dev_priv =3D ims->dev_priv; > > + struct drm_device *dev =3D dev_priv->dev; > > + struct intel_context *ctx; > > + > > +> > > > /* > > +> > > > * Wait for any outstanding activity and unbind the mm. Sinc= e > > +> > > > * each context has its own ring, we can simply wait for the = ring > > +> > > > * to idle before invalidating the PASID and flushing the TLB= . > > +> > > > */ > > + mutex_lock(&dev->struct_mutex); > > + list_for_each_entry(ctx, &ims->context_list, mm_list) { > > + intel_ring_idle(ctx->engine[RCS].ringbuf->ring); > > + } > > + > > + intel_iommu_tlb_flush(dev_priv->dev); > > + mutex_unlock(&dev->struct_mutex); >=20 > Erm, what! So you halt the GPU everytime? But you've already=20 > invalidated the shadow PTE -- ah, invalidate-range looks to be a wip. That's the callback for when the MM goes away =E2=80=94 on process exit, or when we unbind the PASID. But it's still suboptimal, and I am strongly resisting the temptation to have a callback from the OS-mode code into the device driver in this code path. For the normal case of unbinding the PASID cleanly, device drivers are expected to flush their queue of requests for a given PASID *before* calling intel_svm_unbind_pasid(). That includes contexts which might be stalled, waiting for a page request. So you're expected to do any ring management in advance. If a process exits uncleanly, exit_mm() happens before exit_files(). So the MM has gone before the i915 driver gets to clean up. In that case, we end up in the intel_mm_release() function and it just clears the page tables and flushes the IOTLB. Accesses will take faults, and the proper cleanup will happen shortly. > > +static void intel_change_pte(struct mmu_notifier *mn, struct mm_struct= *mm, > > +> > > > > > > > unsigned long address, pte_t pte) > > +{ > > +> > > > struct intel_mm_struct *ims =3D container_of(mn, struct intel= _mm_struct, > > +> > > > > > > > > > > > > > notifier); > > +> > > > struct drm_i915_private *dev_priv =3D ims->dev_priv; > > +> > > > struct drm_device *dev =3D dev_priv->dev; > > + > > +> > > > struct intel_context *ctx; > > + > > +> > > > mutex_lock(&dev->struct_mutex); > > +> > > > list_for_each_entry(ctx, &ims->context_list, mm_list) > > +> > > > > > intel_flush_page_locked(dev, ctx->pasid, address); > > +> > > > mutex_unlock(&dev->struct_mutex); >=20 > Suggests you really want a ims->spinlock for context_list instead. We now use a single PASID for all contexts, so we don't need any list traversal like this anyway. > > +struct intel_mm_struct *intel_bind_mm(struct drm_device *dev, > > + struct intel_context *ctx) > > +{ > > + struct drm_i915_private *dev_priv =3D dev->dev_private; > > + struct intel_mm_struct *ims; > > + struct mmu_notifier *mn; > > + int ret; > > + > > + WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); > > + > > + mn =3D mmu_find_ops(current->mm, &intel_mmuops); >=20 > Magic function, I am missing its definition A previous patch in the series exports this. It basically just checks if there is *already* a mmu_notifier registered with the same mmu_notifier_ops structure, and returns it if so. Because of the hairy locking rules around the mmu_notifier, I've done this differently in my own code =E2=80=94 using idr_for_each_entry() on the= IDR I use to allocate PASIDs. That's fine while there is a relatively low number of PASIDs allocated (i.e. a low number of *processes* using PASIDs, since there's one-PASID-per-process). But if we end up with lots, that idr_for_each_entry() might become burdensome and we might need to take another look. =20 > > + if (mn) { > > + ims =3D container_of(mn, struct intel_mm_struct, > > notifier); > > + kref_get(&ims->kref); > > + goto out; > > + } > > + > > + ims =3D kzalloc(sizeof(*ims), GFP_KERNEL); > > + if (!ims) { > > + ret =3D -ENOMEM; > > + goto error; > > + } > > + INIT_LIST_HEAD(&ims->context_list); > > + > > + ims->notifier.ops =3D &intel_mmuops; > > + > > + ret =3D mmu_notifier_register(&ims->notifier, current->mm); >=20 > This has lock inversion between struct_mutex and mm->mmap_sem. I think this is gone, because I no longer take my equivalent pasid_mutex within the mmu_notifier callbacks. Unless I'm missing something. --=20 David Woodhouse Open Source Technology Centre David.Woodhouse@intel.com Intel Corporation --=-pgqSgXbpmTOEpAzoyEsZ Content-Type: application/x-pkcs7-signature; name="smime.p7s" Content-Disposition: attachment; filename="smime.p7s" Content-Transfer-Encoding: base64 MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIISjjCCBicw ggUPoAMCAQICAw3vNzANBgkqhkiG9w0BAQUFADCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0 YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcx ODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgQ2xpZW50IENB MB4XDTE1MDUwNTA5NDM0MVoXDTE2MDUwNTA5NTMzNlowQjEcMBoGA1UEAwwTZHdtdzJAaW5mcmFk ZWFkLm9yZzEiMCAGCSqGSIb3DQEJARYTZHdtdzJAaW5mcmFkZWFkLm9yZzCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAMkbm9kPbx1j/X4RVyf/pPKSYwelcco69TvnQQbKM8m8xkWjXJI1 jpJ1jMaGUZGFToINMSZi7lZawUozudWbXSKy1SikENSTJHffsdRAIlsp+hR8vWvjsKUry6sEdqPG doa5RY7+N4WRusWZDYW/RRWE6i9EL9qV86CVPYqw22UBOUw4/j/HVGCV6TSB8yE5iEwhk/hUuzRr FZm1MJMR7mCS7BCR8Lr5jFY61lWpBiXNXIxLZCvDc26KR5L5tYX43iUVO3fzES1GRVoYnxxk2tmz fcsZG5vK+Trc9L8OZJfkYrEHH3+Iw41MQ0w/djVtYr1+HYldx0QmYXAtnhIj+UMCAwEAAaOCAtkw ggLVMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD BDAdBgNVHQ4EFgQUszC96C3w5/2+d+atSr0IpT26YI4wHwYDVR0jBBgwFoAUU3Ltkpzg2ssBXHx+ ljVO8tS4UYIwHgYDVR0RBBcwFYETZHdtdzJAaW5mcmFkZWFkLm9yZzCCAUwGA1UdIASCAUMwggE/ MIIBOwYLKwYBBAGBtTcBAgMwggEqMC4GCCsGAQUFBwIBFiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNv bS9wb2xpY3kucGRmMIH3BggrBgEFBQcCAjCB6jAnFiBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTADAgEBGoG+VGhpcyBjZXJ0aWZpY2F0ZSB3YXMgaXNzdWVkIGFjY29yZGluZyB0byB0 aGUgQ2xhc3MgMSBWYWxpZGF0aW9uIHJlcXVpcmVtZW50cyBvZiB0aGUgU3RhcnRDb20gQ0EgcG9s aWN5LCByZWxpYW5jZSBvbmx5IGZvciB0aGUgaW50ZW5kZWQgcHVycG9zZSBpbiBjb21wbGlhbmNl IG9mIHRoZSByZWx5aW5nIHBhcnR5IG9ibGlnYXRpb25zLjA2BgNVHR8ELzAtMCugKaAnhiVodHRw Oi8vY3JsLnN0YXJ0c3NsLmNvbS9jcnR1MS1jcmwuY3JsMIGOBggrBgEFBQcBAQSBgTB/MDkGCCsG AQUFBzABhi1odHRwOi8vb2NzcC5zdGFydHNzbC5jb20vc3ViL2NsYXNzMS9jbGllbnQvY2EwQgYI KwYBBQUHMAKGNmh0dHA6Ly9haWEuc3RhcnRzc2wuY29tL2NlcnRzL3N1Yi5jbGFzczEuY2xpZW50 LmNhLmNydDAjBgNVHRIEHDAahhhodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS8wDQYJKoZIhvcNAQEF BQADggEBAHMQmxHHodpS85X8HRyxhvfkys7r+taCNOaNU9cxQu/cZ/6k5nS2qGNMzZ6jb7ueY/V7 7p+4DW/9ZWODDTf4Fz00mh5SSVc20Bz7t+hhxwHd62PZgENh5i76Qq2tw48U8AsYo5damHby1epf neZafLpUkLLO7AGBJIiRVTevdvyXQ0qnixOmKMWyvrhSNGuVIKVdeqLP+102Dwf+dpFyw+j1hz28 jEEKpHa+NR1b2kXuSPi/rMGhexwlJOh4tK8KQ6Ryr0rIN//NSbOgbyYZrzc/ZUWX9V5OA84ChFb2 vkFl0OcYrttp/rhDBLITwffPxSZeoBh9H7zYzkbCXKL3BUIwggYnMIIFD6ADAgECAgMN7zcwDQYJ KoZIhvcNAQEFBQAwgYwxCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSswKQYD VQQLEyJTZWN1cmUgRGlnaXRhbCBDZXJ0aWZpY2F0ZSBTaWduaW5nMTgwNgYDVQQDEy9TdGFydENv bSBDbGFzcyAxIFByaW1hcnkgSW50ZXJtZWRpYXRlIENsaWVudCBDQTAeFw0xNTA1MDUwOTQzNDFa Fw0xNjA1MDUwOTUzMzZaMEIxHDAaBgNVBAMME2R3bXcyQGluZnJhZGVhZC5vcmcxIjAgBgkqhkiG 9w0BCQEWE2R3bXcyQGluZnJhZGVhZC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDJG5vZD28dY/1+EVcn/6TykmMHpXHKOvU750EGyjPJvMZFo1ySNY6SdYzGhlGRhU6CDTEmYu5W WsFKM7nVm10istUopBDUkyR337HUQCJbKfoUfL1r47ClK8urBHajxnaGuUWO/jeFkbrFmQ2Fv0UV hOovRC/alfOglT2KsNtlATlMOP4/x1Rglek0gfMhOYhMIZP4VLs0axWZtTCTEe5gkuwQkfC6+YxW OtZVqQYlzVyMS2Qrw3NuikeS+bWF+N4lFTt38xEtRkVaGJ8cZNrZs33LGRubyvk63PS/DmSX5GKx Bx9/iMONTENMP3Y1bWK9fh2JXcdEJmFwLZ4SI/lDAgMBAAGjggLZMIIC1TAJBgNVHRMEAjAAMAsG A1UdDwQEAwIEsDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwHQYDVR0OBBYEFLMwvegt 8Of9vnfmrUq9CKU9umCOMB8GA1UdIwQYMBaAFFNy7ZKc4NrLAVx8fpY1TvLUuFGCMB4GA1UdEQQX MBWBE2R3bXcyQGluZnJhZGVhZC5vcmcwggFMBgNVHSAEggFDMIIBPzCCATsGCysGAQQBgbU3AQID MIIBKjAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjCB9wYI KwYBBQUHAgIwgeowJxYgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwAwIBARqBvlRo aXMgY2VydGlmaWNhdGUgd2FzIGlzc3VlZCBhY2NvcmRpbmcgdG8gdGhlIENsYXNzIDEgVmFsaWRh dGlvbiByZXF1aXJlbWVudHMgb2YgdGhlIFN0YXJ0Q29tIENBIHBvbGljeSwgcmVsaWFuY2Ugb25s eSBmb3IgdGhlIGludGVuZGVkIHB1cnBvc2UgaW4gY29tcGxpYW5jZSBvZiB0aGUgcmVseWluZyBw YXJ0eSBvYmxpZ2F0aW9ucy4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5zdGFydHNzbC5j b20vY3J0dTEtY3JsLmNybDCBjgYIKwYBBQUHAQEEgYEwfzA5BggrBgEFBQcwAYYtaHR0cDovL29j c3Auc3RhcnRzc2wuY29tL3N1Yi9jbGFzczEvY2xpZW50L2NhMEIGCCsGAQUFBzAChjZodHRwOi8v YWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIuY2xhc3MxLmNsaWVudC5jYS5jcnQwIwYDVR0SBBww GoYYaHR0cDovL3d3dy5zdGFydHNzbC5jb20vMA0GCSqGSIb3DQEBBQUAA4IBAQBzEJsRx6HaUvOV /B0csYb35MrO6/rWgjTmjVPXMULv3Gf+pOZ0tqhjTM2eo2+7nmP1e+6fuA1v/WVjgw03+Bc9NJoe UklXNtAc+7foYccB3etj2YBDYeYu+kKtrcOPFPALGKOXWph28tXqX53mWny6VJCyzuwBgSSIkVU3 r3b8l0NKp4sTpijFsr64UjRrlSClXXqiz/tdNg8H/naRcsPo9Yc9vIxBCqR2vjUdW9pF7kj4v6zB oXscJSToeLSvCkOkcq9KyDf/zUmzoG8mGa83P2VFl/VeTgPOAoRW9r5BZdDnGK7baf64QwSyE8H3 z8UmXqAYfR+82M5Gwlyi9wVCMIIGNDCCBBygAwIBAgIBHjANBgkqhkiG9w0BAQUFADB9MQswCQYD VQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkwHhcNMDcxMDI0MjEwMTU1WhcNMTcxMDI0MjEwMTU1WjCBjDELMAkGA1UEBhMCSUwxFjAU BgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRl IFNpZ25pbmcxODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUg Q2xpZW50IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxwmDzM4t2BqxKaQuE6uW vooyg4ymiEGWVUet1G8SD+rqvyNH4QrvnEIaFHxOhESip7vMz39ScLpNLbL1QpOlPW/tFIzNHS3q d2XRNYG5Sv9RcGE+T4qbLtsjjJbi6sL7Ls/f/X9ftTyhxvxWkf8KW37iKrueKsxw2HqolH7GM6FX 5UfNAwAu4ZifkpmZzU1slBhyWwaQPEPPZRsWoTb7q8hmgv6Nv3Hg9rmA1/VPBIOQ6SKRkHXG0Hhm q1dOFoAFI411+a/9nWm5rcVjGcIWZ2v/43Yksq60jExipA4l5uv9/+Hm33mbgmCszdj/Dthf13tg Av2O83hLJ0exTqfrlwIDAQABo4IBrTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFFNy7ZKc4NrLAVx8fpY1TvLUuFGCMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mH MMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDovL29jc3Auc3RhcnRz c2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9zZnNjYS5jcnQw WwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAj hiFodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGB tTcBAgEwZjAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0 BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRlLnBkZjANBgkq hkiG9w0BAQUFAAOCAgEACoMIfXirLAZcuGOMXq4cuSN3TaFx2H2GvD5VSy/6rV55BYHbWNaPeQn3 oBSU8KgQZn/Kck1JxbLpAxVCNtsxeW1R87ifhsYZ0qjdrA9anrW2MAWCtosmAOT4OxK9QPoSjCMx M3HbkZCDJgnlE8jMopH21BbyAYr7b5EfGRQJNtgWcvqSXwKHnTutR08+Kkn0KAkXCzeQNLeA5LlY UzFyM7kPAp8pIRMQ+seHunmyG642S2+y/qHEdMuGIwpfz3eDF1PdctL04qYK/zu+Qg1Bw0RwgigV Zs/0c5HP2/e9DBHh7eSwtzYlk4AUr6yxLlcwSjOfOmKEQ/Q8tzh0IFiNu9IPuTGAPBn4CPxD0+Ru 8T2wg8/s43R/PT3kd1OEqOJUl7q+h+r6fpvU0Fzxd2tC8Ga6fDEPme+1Nbi+03pVjuZQKbGwKJ66 gEn06WqaxVZC+J8hh/jR0k9mST1iAZPNYulcNJ8tKmVtjYsv0L1TSm2+NwON58tO+pIVzu3DWwSE XSf+qkDavQam+QtEOZxLBXI++aMUEapSn+k3Lxm48ZCYfAWLb/Xj7F5JQMbZvCexglAbYR0kIHqW 5DnsYSdMD/IplJMojx0NBrxJ3fN9dvX2Y6BIXRsF1du4qESm4/3CKuyUV7p9DW3mPlHTGLvYxnyK Qy7VFBkoLINszBrOUeIxggNvMIIDawIBATCBlDCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0 YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcx ODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgQ2xpZW50IENB AgMN7zcwCQYFKw4DAhoFAKCCAa8wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0B CQUxDxcNMTUxMDA5MDcyNDMzWjAjBgkqhkiG9w0BCQQxFgQUd/1pBb+Zb+ligKgszuNSgUA5m90w gaUGCSsGAQQBgjcQBDGBlzCBlDCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0 ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMT L1N0YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgQ2xpZW50IENBAgMN7zcwgacG CyqGSIb3DQEJEAILMYGXoIGUMIGMMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMv U3RhcnRDb20gQ2xhc3MgMSBQcmltYXJ5IEludGVybWVkaWF0ZSBDbGllbnQgQ0ECAw3vNzANBgkq hkiG9w0BAQEFAASCAQCPpjNNAQWQZHJxHgfujMJwxPqitA5jKJ6N2rDe20fewDVAXGbCIiQHzw1b JZO0C+Batw2k77VjYI/ycF0HH3Fd6sRvwKXvHE5Jq3my69jjqfAe/9biLthG3Vm0qSEGL9b89Z8t hupYbfupyIo285+RcbbBU3zJU+CdOvrlj8s+7139nRVNnJjV0Bv/jUtDsVJgOXVZahUXPDexHnAZ h12nZbUjnuIoViY/LatIuQzUB+118eduuuQxuFnChBtUQ9dBRS3XPThJgvalWCX/7rr4fsM2nM1W PsT+uMLM5Y9jdIF/9Q/lIT8Synd0hnetqsDAmAFlRY8J7Oe6HOy+TkEhAAAAAAAA --=-pgqSgXbpmTOEpAzoyEsZ-- --===============0117993118== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KSW50ZWwtZ2Z4 IG1haWxpbmcgbGlzdApJbnRlbC1nZnhAbGlzdHMuZnJlZWRlc2t0b3Aub3JnCmh0dHA6Ly9saXN0 cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9pbnRlbC1nZngK --===============0117993118==--