All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jon Derrick <jonathan.derrick@intel.com>
To: Scott Bauer <scott.bauer@intel.com>
Cc: keith.busch@intel.com, hch@infradead.org,
	Rafael.Antognolli@intel.com, linux-nvme@lists.infradead.org,
	axboe@fb.com, linux-block@vger.kernel.org,
	j.naumann@fu-berlin.de
Subject: Re: [RFC PATCH 2/6] lib: Add Sed-opal library
Date: Tue, 1 Nov 2016 12:56:11 -0600	[thread overview]
Message-ID: <20161101185611.GA1999@localhost.localdomain> (raw)
In-Reply-To: <1477951099-3127-3-git-send-email-scott.bauer@intel.com>

SGkgUmFmYWVsLCBTY290dCwKCgpGaXJzdCBvZmYsIGNvbmdyYXRzIG9uIHRoZSBzZXQhIEl0IGxv
b2tzIGdvb2Qgc28gZmFyLgoKSnVzdCBzb21lIHNtYWxsIG5pdHMgYmVsb3cgc2luY2UgeW91IGhh
dmUgdG8gcmVzcGluIGl0IGFueXdheXMgOikKCk9uIE1vbiwgT2N0IDMxLCAyMDE2IGF0IDAzOjU4
OjE1UE0gLTA2MDAsIFNjb3R0IEJhdWVyIHdyb3RlOgo+IFRoaXMgcGF0Y2ggaW1wbGVtZW50cyB0
aGUgbmVjZXNzYXJ5IGxvZ2ljIHRvIGJyaW5nIGFuIE9wYWwKPiBlbmFibGVkIGRyaXZlIG91dCBv
ZiBhIGZhY3RvcnktZW5hYmxlZCBpbnRvIGEgd29ya2luZwo+IE9wYWwgc3RhdGUuCj4gCj4gVGhp
cyBwYXRjaCBzZXQgYWxzbyBlbmFibGVzIGxvZ2ljIHRvIHNhdmUgYSBwYXNzd29yZCB0bwo+IGJl
IHJlcGxheWVkIGR1cmluZyBhIHJlc3VtZSBmcm9tIHN1c3BlbmQuIFRoZSBrZXkgY2FuIGJlCj4g
c2F2ZWQgaW4gdGhlIGRyaXZlciBvciBpbiB0aGUgS2VybmVsJ3MgS2V5IG1hbmFnbWVudC4KPiAK
PiBTaWduZWQtb2ZmLWJ5OiBTY290dCBCYXVlciA8c2NvdHQuYmF1ZXJAaW50ZWwuY29tPgo+IFNp
Z25lZC1vZmYtYnk6IFJhZmFlbCBBbnRvZ25vbGxpIDxSYWZhZWwuQW50b2dub2xsaUBpbnRlbC5j
b20+Cj4gLS0tCj4gIGxpYi9zZWQtb3BhbC5jICAgICAgICAgIHwgMzMzNyArKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKwo+ICBsaWIvc2VkLW9wYWxfaW50ZXJu
YWwuaCB8ICA1ODYgKysrKysrKysrCj4gIGxpYi9zZWQtb3BhbF9rZXkuYyAgICAgIHwgICA0NiAr
Cj4gIGxpYi9zZWQuYyAgICAgICAgICAgICAgIHwgIDMwMyArKysrKwo+ICA0IGZpbGVzIGNoYW5n
ZWQsIDQyNzIgaW5zZXJ0aW9ucygrKQo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgbGliL3NlZC1vcGFs
LmMKPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGxpYi9zZWQtb3BhbF9pbnRlcm5hbC5oCj4gIGNyZWF0
ZSBtb2RlIDEwMDY0NCBsaWIvc2VkLW9wYWxfa2V5LmMKPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGxp
Yi9zZWQuYwo+IAo+IGRpZmYgLS1naXQgYS9saWIvc2VkLW9wYWwuYyBiL2xpYi9zZWQtb3BhbC5j
Cj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwLi4xMGIzMzQ4Cj4gLS0tIC9k
ZXYvbnVsbAo+ICsrKyBiL2xpYi9zZWQtb3BhbC5jCj4gQEAgLTAsMCArMSwzMzM3IEBACj4gKy8q
Cj4gKyAqIENvcHlyaWdodCDCqSAyMDE2IEludGVsIENvcnBvcmF0aW9uCj4gKyAqCj4gKyAqIFBl
cm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29u
IG9idGFpbmluZyBhCj4gKyAqIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBk
b2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksCj4gKyAqIHRvIGRlYWwgaW4gdGhl
IFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRp
b24KPiArICogdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gs
IGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsCj4gKyAqIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUg
U29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZQo+ICsgKiBTb2Z0d2Fy
ZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRp
b25zOgo+ICsgKgo+ICsgKiBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJt
aXNzaW9uIG5vdGljZSAoaW5jbHVkaW5nIHRoZSBuZXh0Cj4gKyAqIHBhcmFncmFwaCkgc2hhbGwg
YmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUK
PiArICogU29mdHdhcmUuCj4gKyAqCj4gKyAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMg
SVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SCj4gKyAqIElNUExJ
RUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hB
TlRBQklMSVRZLAo+ICsgKiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9O
SU5GUklOR0VNRU5ULiAgSU4gTk8gRVZFTlQgU0hBTEwKPiArICogVEhFIEFVVEhPUlMgT1IgQ09Q
WVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIK
PiArICogTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBP
UiBPVEhFUldJU0UsIEFSSVNJTkcKPiArICogRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04g
V0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUwo+ICsgKiBJTiBU
SEUgU09GVFdBUkUuCj4gKyAqCj4gKyAqIEF1dGhvcnM6Cj4gKyAqICAgIFJhZmFlbCBBbnRvZ25v
bGxpIDxyYWZhZWwuYW50b2dub2xsaUBpbnRlbC5jb20+Cj4gKyAqICAgIFNjb3R0ICBCYXVlciAg
ICAgIDxzY290dC5iYXVlckBpbnRlbC5jb20+Cj4gKyAqLwo+ICsKPiArI2RlZmluZSBwcl9mbXQo
Zm10KSBLQlVJTERfTU9ETkFNRSAiOk9QQUw6ICIgZm10Cj4gKwo+ICsjaW5jbHVkZSA8bGludXgv
ZGVsYXkuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2RldmljZS5oPgo+ICsjaW5jbHVkZSA8bGludXgv
a2VybmVsLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9saXN0Lmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9n
ZW5oZC5oPgo+ICsjaW5jbHVkZSA8bGludXgvc2xhYi5oPgo+ICsjaW5jbHVkZSA8bGludXgvdWFj
Y2Vzcy5oPgo+ICsjaW5jbHVkZSA8dWFwaS9saW51eC9zZWQtb3BhbC5oPgo+ICsjaW5jbHVkZSA8
bGludXgvc2VkLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9zZWQtb3BhbC5oPgo+ICsjaW5jbHVkZSA8
bGludXgvc3RyaW5nLmg+Cj4gKwo+ICsjaW5jbHVkZSAic2VkLW9wYWxfaW50ZXJuYWwuaCIKPiAr
Cj4gKyNkZWZpbmUgSU9fQlVGRkVSX0xFTkdUSCAyMDQ4Cj4gKwo+ICsjZGVmaW5lIE1BWF9UT0tT
IDY0Cj4gKwo+ICtzdHJ1Y3Qgb3BhbF9jbWQgewo+ICsJc3RydWN0IGJsb2NrX2RldmljZSAqYmRl
djsKPiArCXNlY19jYiAqY2I7Cj4gKwl2b2lkICpjYl9kYXRhOwo+ICsKPiArCXNpemVfdCBwb3M7
Cj4gKwl1OCBjbWRfYnVmW0lPX0JVRkZFUl9MRU5HVEggKiAyXTsKPiArCXU4IHJlc3BfYnVmW0lP
X0JVRkZFUl9MRU5HVEggKiAyXTsKPiArCXU4ICpjbWQ7Cj4gKwl1OCAqcmVzcDsKPiArfTsKPiAr
Cj4gKy8qCj4gKyAqIE9uIHRoZSBwYXJzZWQgcmVzcG9uc2UsIHdlIGRvbid0IHN0b3JlIGFnYWlu
IHRoZSB0b2tzIHRoYXQgYXJlIGFscmVhZHkKPiArICogc3RvcmVkIGluIHRoZSByZXNwb25zZSBi
dWZmZXIuIEluc3RlYWQsIGZvciBlYWNoIHRva2VuLCB3ZSBqdXN0IHN0b3JlIGEKPiArICogcG9p
bnRlciB0byB0aGUgcG9zaXRpb24gaW4gdGhlIGJ1ZmZlciB3aGVyZSB0aGUgdG9rZW4gc3RhcnRz
LCBhbmQgdGhlIHNpemUKPiArICogb2YgdGhlIHRva2VuIGluIGJ5dGVzLgo+ICsgKi8KPiArc3Ry
dWN0IG9wYWxfcmVzcF90b2sgewo+ICsJY29uc3QgdTggKnBvczsKPiArCXNpemVfdCBsZW47Cj4g
KwllbnVtIE9QQUxfUkVTUE9OU0VfVE9LRU4gdHlwZTsKPiArCWVudW0gT1BBTF9BVE9NX1dJRFRI
IHdpZHRoOwo+ICsJdW5pb24gewo+ICsJCXU2NCB1Owo+ICsJCXM2NCBzOwo+ICsJfSBzdG9yZWQ7
Cj4gK307Cj4gKwo+ICsvKgo+ICsgKiBGcm9tIHRoZSByZXNwb25zZSBoZWFkZXIgaXQncyBub3Qg
cG9zc2libGUgdG8ga25vdyBob3cgbWFueSB0b2tlbnMgdGhlcmUgYXJlCj4gKyAqIG9uIHRoZSBw
YXlsb2FkLiBTbyB3ZSBoYXJkY29kZSB0aGF0IHRoZSBtYXhpbXVtIHdpbGwgYmUgTUFYX1RPS1Ms
IGFuZCBsYXRlcgo+ICsgKiBpZiB3ZSBzdGFydCBkZWFsaW5nIHdpdGggbWVzc2FnZXMgdGhhdCBo
YXZlIG1vcmUgdGhhbiB0aGF0LCB3ZSBjYW4gaW5jcmVhc2UKPiArICogdGhpcyBudW1iZXIuIFRo
aXMgaXMgZG9uZSB0byBhdm9pZCBoYXZpbmcgdG8gbWFrZSB0d28gcGFzc2VzIHRocm91Z2ggdGhl
Cj4gKyAqIHJlc3BvbnNlLCB0aGUgZmlyc3Qgb25lIGNvdW50aW5nIGhvdyBtYW55IHRva2VucyB3
ZSBoYXZlIGFuZCB0aGUgc2Vjb25kIG9uZQo+ICsgKiBhY3R1YWxseSBzdG9yaW5nIHRoZSBwb3Np
dGlvbnMuCj4gKyAqLwo+ICtzdHJ1Y3QgcGFyc2VkX3Jlc3Agewo+ICsJaW50IG51bTsKPiArCXN0
cnVjdCBvcGFsX3Jlc3BfdG9rIHRva3NbTUFYX1RPS1NdOwo+ICt9Owo+ICsKPiArc3RydWN0IG9w
YWxfZGV2Owo+ICsKPiArdHlwZWRlZiB2b2lkICgqb3BhbF9jYikoaW50IGVycm9yLCBzdHJ1Y3Qg
b3BhbF9kZXYgKmRldik7Cj4gKwo+ICt0eXBlZGVmIGludCAoKm9wYWxfc3RlcCkoc3RydWN0IG9w
YWxfZGV2ICpkZXYpOwo+ICsKPiArc3RydWN0IG9wYWxfY29tcGxldGlvbiB7Cj4gKwlzdHJ1Y3Qg
Y29tcGxldGlvbiBjbWRfY29tcGxldGlvbjsKPiArCWludCBjb21wbGV0aW9uX3N0YXR1czsKPiAr
fTsKPiArCj4gK3N0cnVjdCBvcGFsX2RldiB7Cj4gKwlzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2
Owo+ICsJc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKPiArCXN0cnVjdCBvcGFs
X2xvY2tfdW5sb2NrIGxrdWw7Cj4gKwljb25zdCBvcGFsX3N0ZXAgKmZ1bmNzOwo+ICsJdm9pZCAq
KmZ1bmNfZGF0YTsKPiArCWJvb2wgcmVzdW1lX2Zyb21fc3VzcGVuZDsKPiArCXN0cnVjdCBvcGFs
X3N1c3BlbmRfdW5sayAqcmVzdW1lX2RhdGE7Cj4gKwlzaXplX3QgbnVtX2Z1bmNfZGF0YTsKPiAr
CWF0b21pY190IGluX3VzZTsKPiArCXNlY3Rvcl90IHN0YXJ0Owo+ICsJc2VjdG9yX3QgbGVuZ3Ro
Owo+ICsJdTggbHI7Cj4gKwl1OCBrZXlfdHlwZTsKPiArCXU4IGtleV9uYW1lW09QQUxfS0VZX01B
WF07Cj4gKwlzaXplX3Qga2V5X25hbWVfbGVuOwo+ICsJdTgga2V5W09QQUxfS0VZX01BWF07Cj4g
KwlzaXplX3Qga2V5X2xlbjsKPiArCXUxNiBjb21JRDsKPiArCXUzMiBIU047Cj4gKwl1MzIgVFNO
Owo+ICsJdTY0IGFsaWduOwo+ICsJdTY0IGxvd2VzdF9sYmE7Cj4gKwlzdHJ1Y3QgbGlzdF9oZWFk
IG5vZGU7Cj4gKwljaGFyIGRpc2tfbmFtZVtESVNLX05BTUVfTEVOXTsKPiArCWludCBzdGF0ZTsK
PiArCj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgY21kOwo+ICsJc3RydWN0IHBhcnNlZF9yZXNwIHBhcnNl
ZDsKPiArCj4gKwlzaXplX3QgcHJldl9kX2xlbjsKPiArCXZvaWQgKnByZXZfZGF0YTsKPiArCj4g
KwlzZWNfY2IgKmZpbmFsX2NiOwo+ICsJdm9pZCAqZmluYWxfY2JfZGF0YTsKPiArCW9wYWxfc3Rl
cCBlcnJvcl9jYjsKPiArCXZvaWQgKmVycm9yX2NiX2RhdGE7Cj4gKwlvcGFsX2NiIG9wZXJfY2I7
Cj4gK307Cj4gKwo+ICtMSVNUX0hFQUQob3BhbF9saXN0KTsKPiArREVGSU5FX1NQSU5MT0NLKGxp
c3Rfc3BpbmxvY2spOwo+ICsKPiArc3RhdGljIHZvaWQgcHJpbnRfYnVmZmVyKGNvbnN0IHU4ICpw
dHIsIHUzMiBsZW5ndGgpCj4gK3sKPiArI2lmZGVmIERFQlVHCj4gKwlwcmludF9oZXhfZHVtcF9i
eXRlcygiT1BBTDogIiwgRFVNUF9QUkVGSVhfT0ZGU0VULCBwdHIsIGxlbmd0aCk7Cj4gKwlwcl9k
ZWJ1ZygiXG4iKTsKPiArI2VuZGlmCj4gK30KPiArCj4gKyNkZWZpbmUgVFBFUl9TWU5DX1NVUFBP
UlRFRCBCSVQoMCkKPiArCj4gK3N0YXRpYyBib29sIGNoZWNrX3RwZXIoY29uc3Qgdm9pZCAqZGF0
YSkKPiArewo+ICsJY29uc3Qgc3RydWN0IGQwX3RwZXJfZmVhdHVyZXMgKnRwZXIgPSBkYXRhOwo+
ICsJdTggZmxhZ3MgPSB0cGVyLT5zdXBwb3J0ZWRfZmVhdHVyZXM7Cj4gKwo+ICsJaWYgKCEoZmxh
Z3MgJiBUUEVSX1NZTkNfU1VQUE9SVEVEKSkgewo+ICsJCXByX2VycigiVFBlciBzeW5jIG5vdCBz
dXBwb3J0ZWQuIGZsYWdzID0gJWRcbiIsCj4gKwkJICAgICAgIHRwZXItPnN1cHBvcnRlZF9mZWF0
dXJlcyk7Cj4gKwkJcmV0dXJuIGZhbHNlOwo+ICsJfQo+ICsKPiArCXJldHVybiB0cnVlOwo+ICt9
Cj4gKwo+ICtzdGF0aWMgYm9vbCBjaGVja19TVU0oY29uc3Qgdm9pZCAqZGF0YSkKPiArewo+ICsJ
Y29uc3Qgc3RydWN0IGQwX3NpbmdsZV91c2VyX21vZGUgKnN1bSA9IGRhdGE7Cj4gKwl1MzIgbmxv
ID0gYmUzMl90b19jcHUoc3VtLT5udW1fbG9ja2luZ19vYmplY3RzKTsKPiArCj4gKwlpZiAobmxv
ID09IDApIHsKPiArCQlwcl9lcnIoIk5lZWQgYXQgbGVhc3Qgb25lIGxvY2tpbmcgb2JqZWN0Llxu
Iik7Cj4gKwkJcmV0dXJuIGZhbHNlOwo+ICsJfQo+ICsKPiArCXByX2RlYnVnKCJOdW1iZXIgb2Yg
bG9ja2luZyBvYmplY3RzOiAlZFxuIiwgbmxvKTsKPiArCj4gKwlyZXR1cm4gdHJ1ZTsKPiArfQo+
ICsKPiArc3RhdGljIHUxNiBnZXRfY29tSURfdjEwMChjb25zdCB2b2lkICpkYXRhKQo+ICt7Cj4g
Kwljb25zdCBzdHJ1Y3QgZDBfb3BhbF92MTAwICp2MTAwID0gZGF0YTsKPiArCj4gKwlyZXR1cm4g
YmUxNl90b19jcHUodjEwMC0+YmFzZUNvbUlEKTsKPiArfQo+ICsKPiArc3RhdGljIHUxNiBnZXRf
Y29tSURfdjIwMChjb25zdCB2b2lkICpkYXRhKQo+ICt7Cj4gKwljb25zdCBzdHJ1Y3QgZDBfb3Bh
bF92MjAwICp2MjAwID0gZGF0YTsKPiArCj4gKwlyZXR1cm4gYmUxNl90b19jcHUodjIwMC0+YmFz
ZUNvbUlEKTsKPiArfQo+ICsKPiArc3RhdGljIGludCBfX29wYWxfc2VuZF9jbWQoc3RydWN0IG9w
YWxfc3VzcGVuZF91bmxrICpkYXRhLCB1MTYgY29tSUQsCj4gKwkJCSAgIHZvaWQgKmJ1ZmZlciwg
c2l6ZV90IGJ1Zmxlbiwgc2VjX2NiICpjYiwKPiArCQkJICAgdm9pZCAqY2JfZGF0YSkKPiArewo+
ICsJcmV0dXJuIGRhdGEtPm9wcy5zZW5kKGRhdGEtPmRhdGEsIGNvbUlELCBUQ0dfU0VDUF8wMSwg
YnVmZmVyLCBidWZsZW4sCj4gKwkJCSAgICAgY2IsIGNiX2RhdGEpOwo+ICt9Cj4gK3N0YXRpYyBp
bnQgX29wYWxfc2VuZF9jbWQoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgdTE2IGNvbUlELAo+
ICsJCQkgIHZvaWQgKmJ1ZmZlciwgc2l6ZV90IGJ1ZmxlbiwKPiArCQkJICBzZWNfY2IgKmNiLCB2
b2lkICpjYl9kYXRhKQo+ICt7Cj4gKwljb25zdCBzdHJ1Y3Qgc2VjX29wcyAqb3BzID0gYmRldi0+
YmRfZGlzay0+Zm9wcy0+c2VjX29wczsKPiArCj4gKwlyZXR1cm4gb3BzLT5zZW5kKGJkZXYtPmJk
X2Rpc2stPnByaXZhdGVfZGF0YSwgY29tSUQsCj4gKwkJCSBUQ0dfU0VDUF8wMSwgYnVmZmVyLCBi
dWZsZW4sCj4gKwkJCSBjYiwgY2JfZGF0YSk7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgX19vcGFs
X3JlY3ZfY21kKHN0cnVjdCBvcGFsX3N1c3BlbmRfdW5sayAqZGF0YSwgdTE2IGNvbUlELAo+ICsJ
CQkgICB2b2lkICpidWZmZXIsIHNpemVfdCBidWZsZW4sIHNlY19jYiAqY2IsCj4gKwkJCSAgIHZv
aWQgKmNiX2RhdGEpCj4gK3sKPiArCXJldHVybiBkYXRhLT5vcHMucmVjdihkYXRhLT5kYXRhLCBj
b21JRCwgVENHX1NFQ1BfMDEsIGJ1ZmZlciwgYnVmbGVuLAo+ICsJCQkgICAgIGNiLCBjYl9kYXRh
KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBfb3BhbF9yZWN2X2NtZChzdHJ1Y3QgYmxvY2tfZGV2
aWNlICpiZGV2LCB1MTYgY29tSUQsCj4gKwkJCSAgdm9pZCAqYnVmZmVyLCBzaXplX3QgYnVmbGVu
LAo+ICsJCQkgIHNlY19jYiAqY2IsIHZvaWQgKmNiX2RhdGEpCj4gK3sKPiArCWNvbnN0IHN0cnVj
dCBzZWNfb3BzICpvcHMgPSBiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzOwo+ICsKPiArCXJl
dHVybiBvcHMtPnJlY3YoYmRldi0+YmRfZGlzay0+cHJpdmF0ZV9kYXRhLCBjb21JRCwKPiArCQkJ
IFRDR19TRUNQXzAxLCBidWZmZXIsIGJ1ZmxlbiwKPiArCQkJIGNiLCBjYl9kYXRhKTsKPiArfQo+
ICsKPiArc3RhdGljIHZvaWQgb3BhbF9zZW5kX2NiX2NvbnQoaW50IGVycm9yLCB2b2lkICpkYXRh
KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7Cj4gKwlzaXplX3QgYnVmbGVu
ID0gSU9fQlVGRkVSX0xFTkdUSDsKPiArCXZvaWQgKmJ1ZmZlciA9IGRldi0+Y21kLnJlc3A7Cj4g
KwlzdHJ1Y3Qgb3BhbF9oZWFkZXIgKmhkciA9IGJ1ZmZlcjsKPiArCj4gKwlwcl9kZWJ1ZygiJXM6
IFNlbnQgT1BBTCBjb21tYW5kOiBlcnJvcj0lZCwgb3V0c3RhbmRpbmc9JWQsIG1pblRyYW5zZmVy
PSVkXG4iLAo+ICsJICAgICAgIGRldi0+ZGlza19uYW1lLCBlcnJvciwgaGRyLT5jcC5vdXRzdGFu
ZGluZ0RhdGEsCj4gKwkgICAgICAgaGRyLT5jcC5taW5UcmFuc2Zlcik7Cj4gKwo+ICsJaWYgKGVy
cm9yIHx8IGhkci0+Y3Aub3V0c3RhbmRpbmdEYXRhID09IDAgfHwKPiArCSAgICBoZHItPmNwLm1p
blRyYW5zZmVyICE9IDApIHsKPiArCQlpZiAoZGV2LT5jbWQuY2IpCj4gKwkJCWRldi0+Y21kLmNi
KGVycm9yLCBkZXYtPmNtZC5jYl9kYXRhKTsKPiArCQlyZXR1cm47Cj4gKwl9Cj4gKwo+ICsJbWVt
c2V0KGJ1ZmZlciwgMCwgYnVmbGVuKTsKPiArCWlmIChkZXYtPnJlc3VtZV9mcm9tX3N1c3BlbmQp
Cj4gKwkJX19vcGFsX3JlY3ZfY21kKGRldi0+cmVzdW1lX2RhdGEsIGRldi0+Y29tSUQsCj4gKwkJ
CQlidWZmZXIsIGJ1Zmxlbiwgb3BhbF9zZW5kX2NiX2NvbnQsIGRldik7Cj4gKwllbHNlCj4gKwkJ
X29wYWxfcmVjdl9jbWQoZGV2LT5iZGV2LCBkZXYtPmNvbUlELCBidWZmZXIsIGJ1ZmxlbiwKPiAr
CQkJICAgICAgIG9wYWxfc2VuZF9jYl9jb250LCBkZXYpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9p
ZCBvcGFsX3NlbmRfY2IoaW50IGVycm9yLCB2b2lkICpkYXRhKQo+ICt7Cj4gKwlzdHJ1Y3Qgb3Bh
bF9kZXYgKmRldiA9IGRhdGE7Cj4gKwlzaXplX3QgYnVmbGVuID0gSU9fQlVGRkVSX0xFTkdUSDsK
PiArCXZvaWQgKmJ1ZmZlciA9IGRldi0+Y21kLnJlc3A7Cj4gKwo+ICsJaWYgKGVycm9yKSB7Cj4g
KwkJaWYgKGRldi0+Y21kLmNiKQo+ICsJCQlkZXYtPmNtZC5jYihlcnJvciwgZGV2LT5jbWQuY2Jf
ZGF0YSk7Cj4gKwkJcmV0dXJuOwo+ICsJfQo+ICsKPiArCW1lbXNldChidWZmZXIsIDAsIGJ1Zmxl
bik7Cj4gKwlpZiAoZGV2LT5yZXN1bWVfZnJvbV9zdXNwZW5kKQo+ICsJCV9fb3BhbF9yZWN2X2Nt
ZChkZXYtPnJlc3VtZV9kYXRhLCBkZXYtPmNvbUlELAo+ICsJCQkJYnVmZmVyLCBidWZsZW4sIG9w
YWxfc2VuZF9jYl9jb250LCBkZXYpOwo+ICsJZWxzZQo+ICsJCV9vcGFsX3JlY3ZfY21kKGRldi0+
YmRldiwgZGV2LT5jb21JRCwgYnVmZmVyLCBidWZsZW4sCj4gKwkJCSAgICAgICBvcGFsX3NlbmRf
Y2JfY29udCwgZGV2KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBvcGFsX3NlbmRfcmVjdihzdHJ1
Y3Qgb3BhbF9kZXYgKmRldiwgc2VjX2NiICpjYiwgdm9pZCAqY2JfZGF0YSkKPiArewo+ICsJc2l6
ZV90IGJ1ZmxlbiA9IElPX0JVRkZFUl9MRU5HVEg7Cj4gKwl2b2lkICpidWZmZXIgPSBkZXYtPmNt
ZC5jbWQ7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWRldi0+Y21kLmNiID0gY2I7Cj4gKwlkZXYtPmNt
ZC5jYl9kYXRhID0gY2JfZGF0YTsKPiArCWlmIChkZXYtPnJlc3VtZV9mcm9tX3N1c3BlbmQpCj4g
KwkJcmV0ID0gX19vcGFsX3NlbmRfY21kKGRldi0+cmVzdW1lX2RhdGEsIGRldi0+Y29tSUQsIGJ1
ZmZlciwKPiArCQkJCSAgICAgIGJ1Zmxlbiwgb3BhbF9zZW5kX2NiLCBkZXYpOwo+ICsJZWxzZQo+
ICsJCXJldCA9IF9vcGFsX3NlbmRfY21kKGRldi0+YmRldiwgZGV2LT5jb21JRCwgYnVmZmVyLCBi
dWZsZW4sCj4gKwkJCQkgICAgIG9wYWxfc2VuZF9jYiwgZGV2KTsKPiArCj4gKwlyZXR1cm4gcmV0
Owo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBjaGVja19nZW9tZXRyeShzdHJ1Y3Qgb3BhbF9kZXYg
KmRldiwgY29uc3Qgdm9pZCAqZGF0YSkKPiArewo+ICsJY29uc3Qgc3RydWN0IGQwX2dlb21ldHJ5
X2ZlYXR1cmVzICpnZW8gPSBkYXRhOwo+ICsKPiArCWRldi0+YWxpZ24gPSBnZW8tPmFsaWdubWVu
dF9ncmFudWxhcml0eTsKPiArCWRldi0+bG93ZXN0X2xiYSA9IGdlby0+bG93ZXN0X2FsaWduZWRf
bGJhOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBvcGFsX2Rpc2NvdmVyeTBfZW5kKGludCBlcnJv
ciwgdm9pZCAqZGF0YSkKPiArewo+ICsJYm9vbCBmb3VuZENvbUlEID0gZmFsc2UsIHN1cHBvcnRl
ZCA9IHRydWUsIHNpbmdsZV91c2VyID0gZmFsc2U7Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9
IGRhdGE7Cj4gKwljb25zdCBzdHJ1Y3QgZDBfaGVhZGVyICpoZHI7Cj4gKwljb25zdCB1OCAqZXBv
cywgKmNwb3M7Cj4gKwl1MTYgY29tSUQgPSAwOwo+ICsKPiArCWlmIChlcnJvcikgewo+ICsJCXBy
X2VycigiJXM6IFNlbmRpbmcgZGlzY292ZXJ5MCBmYWlsZWRcbiIsIGRldi0+ZGlza19uYW1lKTsK
PiArCQlnb3RvIGVycl9jYWxsYmFjazsKPiArCX0KPiArCj4gKwllcG9zID0gZGV2LT5jbWQucmVz
cDsKPiArCWNwb3MgPSBkZXYtPmNtZC5yZXNwOwo+ICsJaGRyID0gKHN0cnVjdCBkMF9oZWFkZXIg
KilkZXYtPmNtZC5yZXNwOwo+ICsKPiArCXByaW50X2J1ZmZlcihkZXYtPmNtZC5yZXNwLCBiZTMy
X3RvX2NwdShoZHItPmxlbmd0aCkpOwo+ICsKPiArCWVwb3MgKz0gYmUzMl90b19jcHUoaGRyLT5s
ZW5ndGgpOyAvKiBlbmQgb2YgYnVmZmVyICovCj4gKwljcG9zICs9IHNpemVvZigqaGRyKTsgLyog
Y3VycmVudCBwb3NpdGlvbiBvbiBidWZmZXIgKi8KPiArCj4gKwl3aGlsZSAoY3BvcyA8IGVwb3Mg
JiYgc3VwcG9ydGVkKSB7Cj4gKwkJY29uc3Qgc3RydWN0IGQwX2ZlYXR1cmVzICpib2R5ID0KPiAr
CQkJKGNvbnN0IHN0cnVjdCBkMF9mZWF0dXJlcyAqKWNwb3M7Cj4gKwo+ICsJCXN3aXRjaCAoYmUx
Nl90b19jcHUoYm9keS0+Y29kZSkpIHsKPiArCQljYXNlIEZDX1RQRVI6Cj4gKwkJCXN1cHBvcnRl
ZCA9IGNoZWNrX3RwZXIoYm9keS0+ZmVhdHVyZXMpOwo+ICsJCQlicmVhazsKPiArCQljYXNlIEZD
X1NJTkdMRVVTRVI6Cj4gKwkJCXNpbmdsZV91c2VyID0gY2hlY2tfU1VNKGJvZHktPmZlYXR1cmVz
KTsKPiArCQkJYnJlYWs7Cj4gKwkJY2FzZSBGQ19HRU9NRVRSWToKPiArCQkJY2hlY2tfZ2VvbWV0
cnkoZGV2LCBib2R5KTsKPiArCQkJYnJlYWs7Cj4gKwkJY2FzZSBGQ19MT0NLSU5HOgo+ICsJCWNh
c2UgRkNfRU5URVJQUklTRToKPiArCQljYXNlIEZDX0RBVEFTVE9SRToKPiArCQkJLyogc29tZSBp
Z25vcmVkIHByb3BlcnRpZXMgKi8KPiArCQkJcHJfZGVidWcoIiVzOiBGb3VuZCBPUEFMIGZlYXR1
cmUgZGVzY3JpcHRpb246ICVkXG4iLAo+ICsJCQkJIGRldi0+ZGlza19uYW1lLCBiZTE2X3RvX2Nw
dShib2R5LT5jb2RlKSk7Cj4gKwkJCWJyZWFrOwo+ICsJCWNhc2UgRkNfT1BBTFYxMDA6Cj4gKwkJ
CWNvbUlEID0gZ2V0X2NvbUlEX3YxMDAoYm9keS0+ZmVhdHVyZXMpOwo+ICsJCQlmb3VuZENvbUlE
ID0gdHJ1ZTsKPiArCQkJYnJlYWs7Cj4gKwkJY2FzZSBGQ19PUEFMVjIwMDoKPiArCQkJY29tSUQg
PSBnZXRfY29tSURfdjIwMChib2R5LT5mZWF0dXJlcyk7Cj4gKwkJCWZvdW5kQ29tSUQgPSB0cnVl
Owo+ICsJCQlicmVhazsKPiArCQlkZWZhdWx0Ogo+ICsJCQlpZiAoYmUxNl90b19jcHUoYm9keS0+
Y29kZSkgPiAweGJmZmYpIHsKPiArCQkJCS8qIHZlbmRvciBzcGVjaWZpYywganVzdCBpZ25vcmUg
Ki8KPiArCQkJfSBlbHNlIHsKPiArCQkJCXByX3dhcm4oIiVzOiBPUEFMIFVua25vd24gZmVhdHVy
ZTogJWRcbiIsCj4gKwkJCQkJZGV2LT5kaXNrX25hbWUsIGJlMTZfdG9fY3B1KGJvZHktPmNvZGUp
KTsKPiArCQkJfQpTbWFsbCBuaXQsIGhvdyBhYm91dDoKCmNhc2UgMHhiZmZmIC4uLiAweGZmZmY6
CgkvKiB2ZW5kb3Igc3BlY2lmaWMsIGp1c3QgaWdub3JlICovCglicmVhazsKZGVmYXVsdDoKCXBy
X3dhcm4oLi4uCgoKCj4gKwkJfQo+ICsJCWNwb3MgKz0gYm9keS0+bGVuZ3RoICsgNDsKPiArCX0K
PiArCj4gKwlpZiAoIXN1cHBvcnRlZCkgewo+ICsJCXByX2VycigiJXM6IERldmljZSBub3Qgc3Vw
cG9ydGVkXG4iLCBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJZ290byBlcnJfY2FsbGJhY2s7Cj4gKwl9
Cj4gKwo+ICsJaWYgKCFzaW5nbGVfdXNlcikKPiArCQlwcl93YXJuKCIlczogRGV2aWNlIGRvZXNu
J3Qgc3VwcG9ydCBzaW5nbGUgdXNlciBtb2RlXG4iLAo+ICsJCQlkZXYtPmRpc2tfbmFtZSk7Cj4g
Kwo+ICsJaWYgKCFmb3VuZENvbUlEKSB7Cj4gKwkJcHJfd2FybigiJXM6IENvdWxkIG5vdCBmaW5k
IE9QQUwgY29tSUQgZm9yIGRldmljZS4gT1BBTCBrZXJuZWwgdW5sb2NraW5nIHdpbGwgYmUgZGlz
YWJsZWRcbiIsCj4gKwkJCWRldi0+ZGlza19uYW1lKTsKPiArCQlnb3RvIGVycl9jYWxsYmFjazsK
PiArCX0KPiArCj4gKwlkZXYtPmNvbUlEID0gY29tSUQ7Cj4gKwo+ICtlcnJfY2FsbGJhY2s6Cj4g
KwlpZiAoZGV2LT5vcGVyX2NiKQo+ICsJCWRldi0+b3Blcl9jYihlcnJvciwgZGV2KTsKPiArfQo+
ICsKPiArc3RhdGljIGludCBvcGFsX2Rpc2NvdmVyeTAoc3RydWN0IG9wYWxfZGV2ICpkZXYpCj4g
K3sKPiArCW1lbXNldChkZXYtPmNtZC5yZXNwLCAwLCBJT19CVUZGRVJfTEVOR1RIKTsKPiArCj4g
KwlpZiAoZGV2LT5yZXN1bWVfZnJvbV9zdXNwZW5kKQo+ICsJCXJldHVybiBfX29wYWxfcmVjdl9j
bWQoZGV2LT5yZXN1bWVfZGF0YSwgMHgwMDAxLAo+ICsJCQkJICAgICAgIGRldi0+Y21kLnJlc3As
IElPX0JVRkZFUl9MRU5HVEgsCj4gKwkJCQkgICAgICAgb3BhbF9kaXNjb3ZlcnkwX2VuZCwgZGV2
KTsKPiArCj4gKwlyZXR1cm4gX29wYWxfcmVjdl9jbWQoZGV2LT5iZGV2LCAweDAwMDEsIGRldi0+
Y21kLnJlc3AsCj4gKwkJCSAgICAgIElPX0JVRkZFUl9MRU5HVEgsIG9wYWxfZGlzY292ZXJ5MF9l
bmQsCj4gKwkJCSAgICAgIGRldik7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGFkZF90b2tlbl91
OChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgdTggdG9rKQo+ICt7Cj4gKwljbWQtPmNtZFtjbWQtPnBv
cysrXSA9IHRvazsKPiArfQo+ICsKPiArc3RhdGljIHNzaXplX3QgdGVzdF9hbmRfYWRkX3Rva2Vu
X3U4KHN0cnVjdCBvcGFsX2NtZCAqY21kLCB1OCB0b2spCj4gK3sKPiArCUJVSUxEX0JVR19PTihJ
T19CVUZGRVJfTEVOR1RIID49IFNJWkVfTUFYKTsKPiArCj4gKwlpZiAoY21kLT5wb3MgPj0gSU9f
QlVGRkVSX0xFTkdUSCAtIDEpIHsKPiArCQlwcl9lcnIoIkVycm9yIGFkZGluZyB1ODogZW5kIG9m
IGJ1ZmZlci5cbiIpOwo+ICsJCXJldHVybiAtRVJBTkdFOwo+ICsJfQo+ICsKPiArCWFkZF90b2tl
bl91OChjbWQsIHRvayk7Cj4gKwo+ICsJcmV0dXJuIDE7Cj4gK30KPiArCj4gKyNkZWZpbmUgVElO
WV9BVE9NX0RBVEFfTUFTSyBHRU5NQVNLKDUsIDApCj4gKyNkZWZpbmUgVElOWV9BVE9NX1NJR05F
RCBCSVQoNikKPiArCj4gKyNkZWZpbmUgU0hPUlRfQVRPTV9JRCBCSVQoNykKPiArI2RlZmluZSBT
SE9SVF9BVE9NX0JZVEVTVFJJTkcgQklUKDUpCj4gKyNkZWZpbmUgU0hPUlRfQVRPTV9TSUdORUQg
QklUKDQpCj4gKyNkZWZpbmUgU0hPUlRfQVRPTV9MRU5fTUFTSyBHRU5NQVNLKDMsIDApCj4gKwo+
ICtzdGF0aWMgdm9pZCBhZGRfc2hvcnRfYXRvbV9oZWFkZXIoc3RydWN0IG9wYWxfY21kICpjbWQs
IGJvb2wgYnl0ZXN0cmluZywKPiArCQkJCSAgYm9vbCBoYXNfc2lnbiwgaW50IGxlbikKPiArewo+
ICsJdTggYXRvbTsKPiArCj4gKwlhdG9tID0gU0hPUlRfQVRPTV9JRDsKPiArCWF0b20gfD0gYnl0
ZXN0cmluZyA/IFNIT1JUX0FUT01fQllURVNUUklORyA6IDA7Cj4gKwlhdG9tIHw9IGhhc19zaWdu
ID8gU0hPUlRfQVRPTV9TSUdORUQgOiAwOwo+ICsJYXRvbSB8PSBsZW4gJiBTSE9SVF9BVE9NX0xF
Tl9NQVNLOwo+ICsKPiArCWFkZF90b2tlbl91OChjbWQsIGF0b20pOwo+ICt9Cj4gKwo+ICsjZGVm
aW5lIE1FRElVTV9BVE9NX0lEIChCSVQoNykgfCBCSVQoNikpCj4gKyNkZWZpbmUgTUVESVVNX0FU
T01fQllURVNUUklORyBCSVQoNCkKPiArI2RlZmluZSBNRURJVU1fQVRPTV9TSUdORUQgQklUKDMp
Cj4gKyNkZWZpbmUgTUVESVVNX0FUT01fTEVOX01BU0sgR0VOTUFTSygyLCAwKQo+ICsKPiArc3Rh
dGljIHZvaWQgYWRkX21lZGl1bV9hdG9tX2hlYWRlcihzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgYm9v
bCBieXRlc3RyaW5nLAo+ICsJCQkJICAgYm9vbCBoYXNfc2lnbiwgaW50IGxlbikKPiArewo+ICsJ
dTggaGVhZGVyMDsKPiArCj4gKwloZWFkZXIwID0gTUVESVVNX0FUT01fSUQ7Cj4gKwloZWFkZXIw
IHw9IGJ5dGVzdHJpbmcgPyBNRURJVU1fQVRPTV9CWVRFU1RSSU5HIDogMDsKPiArCWhlYWRlcjAg
fD0gaGFzX3NpZ24gPyBNRURJVU1fQVRPTV9TSUdORUQgOiAwOwo+ICsJaGVhZGVyMCB8PSAobGVu
ID4+IDgpICYgTUVESVVNX0FUT01fTEVOX01BU0s7Cj4gKwljbWQtPmNtZFtjbWQtPnBvcysrXSA9
IGhlYWRlcjA7Cj4gKwljbWQtPmNtZFtjbWQtPnBvcysrXSA9IGxlbjsKPiArfQo+ICsKPiArc3Rh
dGljIHZvaWQgYWRkX3Rva2VuX3U2NChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgdTY0IG51bWJlciwg
c2l6ZV90IGxlbikKPiArewo+ICsJYWRkX3Nob3J0X2F0b21faGVhZGVyKGNtZCwgZmFsc2UsIGZh
bHNlLCBsZW4pOwo+ICsKPiArCXdoaWxlIChsZW4tLSkgewo+ICsJCXU4IG4gPSBudW1iZXIgPj4g
KGxlbiAqIDgpOwo+ICsKPiArCQlhZGRfdG9rZW5fdTgoY21kLCBuKTsKPiArCX0KPiArfQo+ICsK
PiArc3RhdGljIHNzaXplX3QgdGVzdF9hbmRfYWRkX3Rva2VuX3U2NChzdHJ1Y3Qgb3BhbF9jbWQg
KmNtZCwgdTY0IG51bWJlcikKPiArewo+ICsJaW50IGxlbjsKPiArCWludCBtc2I7Cj4gKwo+ICsJ
aWYgKCEobnVtYmVyICYgflRJTllfQVRPTV9EQVRBX01BU0spKQo+ICsJCXJldHVybiB0ZXN0X2Fu
ZF9hZGRfdG9rZW5fdTgoY21kLCBudW1iZXIpOwo+ICsKPiArCW1zYiA9IGZscyhudW1iZXIpOwo+
ICsJbGVuID0gRElWX1JPVU5EX1VQKG1zYiwgNCk7Cj4gKwo+ICsJaWYgKGNtZC0+cG9zID49IElP
X0JVRkZFUl9MRU5HVEggLSBsZW4gLSAxKSB7Cj4gKwkJcHJfZXJyKCJFcnJvciBhZGRpbmcgdTY0
OiBlbmQgb2YgYnVmZmVyLlxuIik7Cj4gKwkJcmV0dXJuIC1FUkFOR0U7Cj4gKwl9Cj4gKwo+ICsJ
YWRkX3Rva2VuX3U2NChjbWQsIG51bWJlciwgbGVuKTsKPiArCj4gKwkvKiByZXR1cm4gbGVuZ3Ro
IG9mIHRva2VuIHBsdXMgYXRvbSAqLwo+ICsJcmV0dXJuIGxlbiArIDE7Cj4gK30KPiArCj4gK3N0
YXRpYyB2b2lkIGFkZF90b2tlbl9ieXRlc3RyaW5nKHN0cnVjdCBvcGFsX2NtZCAqY21kLAo+ICsJ
CQkJIGNvbnN0IHU4ICpieXRlc3RyaW5nLCBzaXplX3QgbGVuKQo+ICt7Cj4gKwltZW1jcHkoJmNt
ZC0+Y21kW2NtZC0+cG9zXSwgYnl0ZXN0cmluZywgbGVuKTsKPiArCWNtZC0+cG9zICs9IGxlbjsK
PiArfQo+ICsKPiArc3RhdGljIHNzaXplX3QgdGVzdF9hbmRfYWRkX3Rva2VuX2J5dGVzdHJpbmco
c3RydWN0IG9wYWxfY21kICpjbWQsCj4gKwkJCQkJICAgICBjb25zdCB1OCAqYnl0ZXN0cmluZywg
c2l6ZV90IGxlbikKPiArewo+ICsJc2l6ZV90IGhlYWRlcl9sZW4gPSAxOwo+ICsJYm9vbCBpc19z
aG9ydF9hdG9tID0gdHJ1ZTsKPiArCj4gKwlpZiAobGVuICYgflNIT1JUX0FUT01fTEVOX01BU0sp
IHsKPiArCQloZWFkZXJfbGVuID0gMjsKPiArCQlpc19zaG9ydF9hdG9tID0gZmFsc2U7Cj4gKwl9
Cj4gKwo+ICsJaWYgKGNtZC0+cG9zID49IElPX0JVRkZFUl9MRU5HVEggLSBsZW4gLSBoZWFkZXJf
bGVuKSB7Cj4gKwkJcHJfZXJyKCJFcnJvciBhZGRpbmcgYnl0ZXN0cmluZzogZW5kIG9mIGJ1ZmZl
ci5cbiIpOwo+ICsJCXJldHVybiAtRVJBTkdFOwo+ICsJfQo+ICsKPiArCWlmIChpc19zaG9ydF9h
dG9tKQo+ICsJCWFkZF9zaG9ydF9hdG9tX2hlYWRlcihjbWQsIHRydWUsIGZhbHNlLCBsZW4pOwo+
ICsJZWxzZQo+ICsJCWFkZF9tZWRpdW1fYXRvbV9oZWFkZXIoY21kLCB0cnVlLCBmYWxzZSwgbGVu
KTsKPiArCj4gKwlhZGRfdG9rZW5fYnl0ZXN0cmluZyhjbWQsIGJ5dGVzdHJpbmcsIGxlbik7Cj4g
Kwo+ICsJcmV0dXJuIGhlYWRlcl9sZW4gKyBsZW47Cj4gK30KPiArCj4gKyNkZWZpbmUgTE9DS0lO
R19SQU5HRV9OT05fR0xPQkFMIDB4MDMKPiArCj4gK3N0YXRpYyBpbnQgYnVpbGRfbG9ja2luZ19y
YW5nZSh1OCAqYnVmZmVyLCBzaXplX3QgbGVuZ3RoLCB1OCBscikKPiArewo+ICsJaWYgKGxlbmd0
aCA8IE9QQUxfVUlEX0xFTkdUSCkKPiArCQlyZXR1cm4gLUVSQU5HRTsKPiArCj4gKwltZW1jcHko
YnVmZmVyLCBPUEFMVUlEW09QQUxfTE9DS0lOR1JBTkdFX0dMT0JBTF0sIE9QQUxfVUlEX0xFTkdU
SCk7Cj4gKwo+ICsJaWYgKGxyID09IDApCj4gKwkJcmV0dXJuIDA7Cj4gKwlidWZmZXJbNV0gPSBM
T0NLSU5HX1JBTkdFX05PTl9HTE9CQUw7Cj4gKwlidWZmZXJbN10gPSBscjsKPiArCj4gKwlyZXR1
cm4gMDsKPiArfQo+ICsKPiArc3RhdGljIGludCBidWlsZF9sb2NraW5nX3VzZXIodTggKmJ1ZmZl
ciwgc2l6ZV90IGxlbmd0aCwgdTggbHIpCj4gK3sKPiArCWlmIChsZW5ndGggPCBPUEFMX1VJRF9M
RU5HVEgpCj4gKwkJcmV0dXJuIC1FUkFOR0U7Cj4gKwo+ICsJbWVtY3B5KGJ1ZmZlciwgT1BBTFVJ
RFtPUEFMX1VTRVIxX1VJRF0sIE9QQUxfVUlEX0xFTkdUSCk7Cj4gKwo+ICsJYnVmZmVyWzddID0g
bHIgKyAxOwo+ICsKPiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ICsvKgo+ICsgKiBOID0gbnVtYmVy
IG9mIGZvcm1hdCBzcGVjaWZpZXJzICgxLTk5OSkgdG8gYmUgcmVwbGljYXRlZAo+ICsgKiBjID0g
dTgKPiArICogdSA9IHU2NAo+ICsgKiBzID0gYnl0ZXN0cmluZywgbGVuZ3RoCj4gKyAqCj4gKyAq
IHJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjIiwKPiArICoJCQkgICAgICAgdThf
dmFsMSk7Cj4gKyAqCj4gKyAqIHJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICIyYzJ1
IiwKPiArICoJCQkgICAgICAgdThfdmFsMSwgdThfdmFsMiwgdTY0X3ZhbDEsIHU2NF92YWwyKTsK
PiArICoKPiArICogcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgIjNzIiwKPiArICoJ
CQkgICAgICAgYnl0ZXN0cmluZzEsIGxlbmd0aDEsCj4gKyAqCQkJICAgICAgIGJ5dGVzdHJpbmcy
LCBsZW5ndGgyLAo+ICsgKgkJCSAgICAgICBieXRlc3RyaW5nMywgbGVuZ3RoMyk7Cj4gKyAqLwo+
ICtzdGF0aWMgaW50IHRlc3RfYW5kX2FkZF90b2tlbl92YShzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwK
PiArCQkJCSBjb25zdCBjaGFyICpmbXQsIC4uLikKPiArewo+ICsJY29uc3QgdTggKml0ID0gZm10
LCAqdG1wOwo+ICsJaW50IHJldCwgbnVtID0gMSwgc3VtID0gMDsKPiArCXZhX2xpc3QgYXA7Cj4g
Kwo+ICsJdmFfc3RhcnQoYXAsIGZtdCk7Cj4gKwo+ICsJd2hpbGUgKCppdCAhPSAnXDAnKSB7Cj4g
KwkJdTY0IHRvazY0ID0gMDsKPiArCQl1OCB0b2ssICpic3RyOwo+ICsJCXNpemVfdCBsZW47Cj4g
Kwo+ICsJCXJldCA9IDA7Cj4gKwo+ICsJCXN3aXRjaCAoKml0KSB7Cj4gKwkJY2FzZSAnMScgLi4u
ICc5JzoKPiArCQkJdG1wID0gaXQ7Cj4gKwkJCW51bSA9IDA7Cj4gKwkJCXdoaWxlICgqdG1wID49
ICcwJyAmJiAqdG1wIDw9ICc5JykKPiArCQkJCW51bSA9IG51bSAqIDEwICsgKCp0bXArKyAtICcw
Jyk7Cj4gKwkJCWl0ID0gdG1wOwo+ICsJCQljb250aW51ZTsKPiArCQljYXNlICdjJzoKPiArCQkJ
d2hpbGUgKG51bS0tKSB7Cj4gKwkJCQl0b2sgPSB2YV9hcmcoYXAsIHVuc2lnbmVkIGludCk7Cj4g
KwkJCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdTgoY21kLCB0b2spOwo+ICsJCQkJaWYgKHJl
dCA8IDApCj4gKwkJCQkJZ290byBlcnI7Cj4gKwkJCX0KPiArCQkJbnVtID0gMTsKPiArCQkJYnJl
YWs7Cj4gKwkJY2FzZSAndSc6Cj4gKwkJCXdoaWxlIChudW0tLSkgewo+ICsJCQkJdG9rNjQgPSB2
YV9hcmcoYXAsIHU2NCk7Cj4gKwkJCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdTY0KGNtZCwg
dG9rNjQpOwo+ICsJCQkJaWYgKHJldCA8IDApCj4gKwkJCQkJZ290byBlcnI7Cj4gKwkJCX0KPiAr
CQkJbnVtID0gMTsKPiArCQkJYnJlYWs7Cj4gKwkJY2FzZSAncyc6Cj4gKwkJCXdoaWxlIChudW0t
LSkgewo+ICsJCQkJYnN0ciA9IHZhX2FyZyhhcCwgdTggKik7Cj4gKwkJCQlsZW4gPSB2YV9hcmco
YXAsIHNpemVfdCk7Cj4gKwkJCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fYnl0ZXN0cmluZyhj
bWQsIGJzdHIsCj4gKwkJCQkJCQkJICAgIGxlbik7Cj4gKwkJCQlpZiAocmV0IDwgMCkKPiArCQkJ
CQlnb3RvIGVycjsKPiArCQkJfQo+ICsJCQludW0gPSAxOwo+ICsJCQlicmVhazsKPiArCQljYXNl
ICcgJzoKPiArCQljYXNlICdcdCc6Cj4gKwkJCS8qIGlnbm9yZWQgKi8KPiArCQkJYnJlYWs7Cj4g
KwkJZGVmYXVsdDoKPiArCQkJcHJfd2FybigiVW5yZWNvZ25pemVkIHR5cGUuXG4iKTsKPiArCQl9
Cj4gKwo+ICsJCWl0Kys7Cj4gKwkJc3VtICs9IHJldDsKPiArCX0KPiArCj4gKwl2YV9lbmQoYXAp
Owo+ICsKPiArCXJldHVybiBzdW07Cj4gKwo+ICsgZXJyOgo+ICsJcHJfZXJyKCJUb2tlbiBmYWls
ZWQgdG8gYmUgYWRkZWQuXG4iKTsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRpYyB2
b2lkIHNldF9jb21JRChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgdTE2IGNvbUlEKQo+ICt7Cj4gKwlz
dHJ1Y3Qgb3BhbF9oZWFkZXIgKmhkciA9IChzdHJ1Y3Qgb3BhbF9oZWFkZXIgKiljbWQtPmNtZDsK
PiArCj4gKwloZHItPmNwLmV4dGVuZGVkQ29tSURbMF0gPSBjb21JRCA+PiA4Owo+ICsJaGRyLT5j
cC5leHRlbmRlZENvbUlEWzFdID0gY29tSUQ7Cj4gKwloZHItPmNwLmV4dGVuZGVkQ29tSURbMl0g
PSAwOwo+ICsJaGRyLT5jcC5leHRlbmRlZENvbUlEWzNdID0gMDsKPiArfQo+ICsKPiArc3RhdGlj
IGludCBjbWRfZmluYWxpemUoc3RydWN0IG9wYWxfY21kICpjbWQsIHUzMiBoc24sIHUzMiB0c24p
Cj4gK3sKPiArCXN0cnVjdCBvcGFsX2hlYWRlciAqaGRyOwo+ICsJaW50IHJldDsKPiArCj4gKwly
ZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiNmMiLAo+ICsJCQkJICAgIE9QQUxfRU5E
T0ZEQVRBLCBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICAwLCAwLCAwLCBPUEFMX0VORExJU1Qp
Owo+ICsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCJFcnJvciBmaW5hbGl6aW5nIGNv
bW1hbmQuXG4iKTsKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiArCX0KPiArCj4gKwloZHIgPSAoc3Ry
dWN0IG9wYWxfaGVhZGVyICopIGNtZC0+Y21kOwo+ICsKPiArCWhkci0+cGt0LlRTTiA9IGNwdV90
b19iZTMyKHRzbik7Cj4gKwloZHItPnBrdC5IU04gPSBjcHVfdG9fYmUzMihoc24pOwo+ICsKPiAr
CWhkci0+c3VicGt0Lmxlbmd0aCA9IGNwdV90b19iZTMyKGNtZC0+cG9zIC0gc2l6ZW9mKCpoZHIp
KTsKPiArCXdoaWxlIChjbWQtPnBvcyAlIDQpIHsKPiArCQlpZiAoY21kLT5wb3MgPj0gSU9fQlVG
RkVSX0xFTkdUSCkgewo+ICsJCQlwcl9lcnIoIkVycm9yOiBCdWZmZXIgb3ZlcnJ1blxuIik7Cj4g
KwkJCXJldHVybiAtRVJBTkdFOwo+ICsJCX0KPiArCQljbWQtPmNtZFtjbWQtPnBvcysrXSA9IDA7
Cj4gKwl9Cj4gKwloZHItPnBrdC5sZW5ndGggPSBjcHVfdG9fYmUzMihjbWQtPnBvcyAtIHNpemVv
ZihoZHItPmNwKSAtCj4gKwkJCQkgICAgICBzaXplb2YoaGRyLT5wa3QpKTsKPiArCWhkci0+Y3Au
bGVuZ3RoID0gY3B1X3RvX2JlMzIoY21kLT5wb3MgLSBzaXplb2YoaGRyLT5jcCkpOwo+ICsKPiAr
CXJldHVybiAwOwo+ICt9Cj4gKwo+ICtzdGF0aWMgZW51bSBPUEFMX1JFU1BPTlNFX1RPS0VOIHRv
a2VuX3R5cGUoY29uc3Qgc3RydWN0IHBhcnNlZF9yZXNwICpyZXNwLAo+ICsJCQkJCSAgIGludCBu
KQo+ICt7Cj4gKwljb25zdCBzdHJ1Y3Qgb3BhbF9yZXNwX3RvayAqdG9rOwo+ICsKPiArCWlmIChu
ID49IHJlc3AtPm51bSkgewo+ICsJCXByX2VycigiVG9rZW4gbnVtYmVyIGRvZXNuJ3QgZXhpc3Q6
ICVkLCByZXNwOiAlZFxuIiwKPiArCQkgICAgICAgbiwgcmVzcC0+bnVtKTsKPiArCQlyZXR1cm4g
T1BBTF9EVEFfVE9LRU5JRF9JTlZBTElEOwo+ICsJfQo+ICsKPiArCXRvayA9ICZyZXNwLT50b2tz
W25dOwo+ICsJaWYgKHRvay0+bGVuID09IDApIHsKPiArCQlwcl9lcnIoIlRva2VuIGxlbmd0aCBt
dXN0IGJlIG5vbi16ZXJvXG4iKTsKPiArCQlyZXR1cm4gT1BBTF9EVEFfVE9LRU5JRF9JTlZBTElE
Owo+ICsJfQo+ICsKPiArCXJldHVybiB0b2stPnR5cGU7Cj4gK30KPiArCj4gKy8qCj4gKyAqIFRo
aXMgZnVuY3Rpb24gcmV0dXJucyAwIGluIGNhc2Ugb2YgaW52YWxpZCB0b2tlbi4gT25lIHNob3Vs
ZCBjYWxsCj4gKyAqIHRva2VuX3R5cGUoKSBmaXJzdCB0byBmaW5kIG91dCBpZiB0aGUgdG9rZW4g
aXMgdmFsaWQgb3Igbm90Lgo+ICsgKi8KPiArc3RhdGljIGVudW0gT1BBTF9UT0tFTiByZXNwb25z
ZV9nZXRfdG9rZW4oY29uc3Qgc3RydWN0IHBhcnNlZF9yZXNwICpyZXNwLAo+ICsJCQkJCSAgaW50
IG4pCj4gK3sKPiArCWNvbnN0IHN0cnVjdCBvcGFsX3Jlc3BfdG9rICp0b2s7Cj4gKwo+ICsJaWYg
KG4gPj0gcmVzcC0+bnVtKSB7Cj4gKwkJcHJfZXJyKCJUb2tlbiBudW1iZXIgZG9lc24ndCBleGlz
dDogJWQsIHJlc3A6ICVkXG4iLAo+ICsJCSAgICAgICBuLCByZXNwLT5udW0pOwo+ICsJCXJldHVy
biAwOwo+ICsJfQo+ICsKPiArCXRvayA9ICZyZXNwLT50b2tzW25dOwo+ICsJaWYgKHRvay0+bGVu
ID09IDApIHsKPiArCQlwcl9lcnIoIlRva2VuIGxlbmd0aCBtdXN0IGJlIG5vbi16ZXJvXG4iKTsK
PiArCQlyZXR1cm4gMDsKPiArCX0KPiArCj4gKwlyZXR1cm4gdG9rLT5wb3NbMF07Cj4gK30KPiAr
Cj4gK3N0YXRpYyBzaXplX3QgcmVzcG9uc2VfcGFyc2VfdGlueShzdHJ1Y3Qgb3BhbF9yZXNwX3Rv
ayAqdG9rLAo+ICsJCQkJICBjb25zdCB1OCAqcG9zKQo+ICt7Cj4gKwl0b2stPnBvcyA9IHBvczsK
PiArCXRvay0+bGVuID0gMTsKPiArCXRvay0+d2lkdGggPSBPUEFMX1dJRFRIX1RJTlk7Cj4gKwo+
ICsJaWYgKHBvc1swXSAmIFRJTllfQVRPTV9TSUdORUQpIHsKPiArCQl0b2stPnR5cGUgPSBPUEFM
X0RUQV9UT0tFTklEX1NJTlQ7Cj4gKwl9IGVsc2Ugewo+ICsJCXRvay0+dHlwZSA9IE9QQUxfRFRB
X1RPS0VOSURfVUlOVDsKPiArCQl0b2stPnN0b3JlZC51ID0gcG9zWzBdICYgMHgzZjsKPiArCX0K
PiArCj4gKwlyZXR1cm4gdG9rLT5sZW47Cj4gK30KPiArCj4gK3N0YXRpYyBzaXplX3QgcmVzcG9u
c2VfcGFyc2Vfc2hvcnQoc3RydWN0IG9wYWxfcmVzcF90b2sgKnRvaywKPiArCQkJCSAgIGNvbnN0
IHU4ICpwb3MpCj4gK3sKPiArCXRvay0+cG9zID0gcG9zOwo+ICsJdG9rLT5sZW4gPSAocG9zWzBd
ICYgU0hPUlRfQVRPTV9MRU5fTUFTSykgKyAxOwo+ICsJdG9rLT53aWR0aCA9IE9QQUxfV0lEVEhf
U0hPUlQ7Cj4gKwo+ICsJaWYgKHBvc1swXSAmIFNIT1JUX0FUT01fQllURVNUUklORykgewo+ICsJ
CXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfQllURVNUUklORzsKPiArCX0gZWxzZSBpZiAo
cG9zWzBdICYgU0hPUlRfQVRPTV9TSUdORUQpIHsKPiArCQl0b2stPnR5cGUgPSBPUEFMX0RUQV9U
T0tFTklEX1NJTlQ7Cj4gKwl9IGVsc2Ugewo+ICsJCXU2NCB1X2ludGVnZXIgPSAwOwo+ICsJCWlu
dCBpLCBiID0gMDsKPiArCj4gKwkJdG9rLT50eXBlID0gT1BBTF9EVEFfVE9LRU5JRF9VSU5UOwo+
ICsJCWlmICh0b2stPmxlbiA+IDkpClNob3VsZCB0aGlzIGJlIGxlbiA+IDggb3IgbGVuID49IDkg
PwoKPiArCQkJcHJfd2FybigidWludDY0IHdpdGggbW9yZSB0aGFuIDggYnl0ZXNcbiIpOwo+ICsJ
CWZvciAoaSA9IHRvay0+bGVuIC0gMTsgaSA+IDA7IGktLSkgewo+ICsJCQl1X2ludGVnZXIgfD0g
KCh1NjQpcG9zW2ldIDw8ICg4ICogYikpOwo+ICsJCQliKys7Cj4gKwkJfQpJdCBkb2Vzbid0IGxv
b2sgcGFydGljdWxhcmx5IHNhZmUgdG8ga2VlcCB1c2luZyB0aGlzIGRyaXZlciBvbiBhIGRyaXZl
CmlmIGl0IHJldHVybnMgYSBsZW4gPiA4LiBCdXQgdGhlIHNwZWNzIGRvIGFsbG93IDE2LWJ5dGUg
ZGF0YSBpbiBhIHNob3J0CmF0b20sIHNvIG1heWJlIHdlIHNob3VsZCBiYWlsIG9uIGFsbG93aW5n
IHRoZSBkcml2ZXIgdG8gbWFuYWdlIHRoZQpkcml2ZSwgb3IgY2hhbmdlIHRoZSB0eXBlcyB0byBz
b21lIDE2LWJ5dGUgdHlwZT8KCj4gKwkJdG9rLT5zdG9yZWQudSA9IHVfaW50ZWdlcjsKPiArCX0K
PiArCj4gKwlyZXR1cm4gdG9rLT5sZW47Cj4gK30KPiArCj4gK3N0YXRpYyBzaXplX3QgcmVzcG9u
c2VfcGFyc2VfbWVkaXVtKHN0cnVjdCBvcGFsX3Jlc3BfdG9rICp0b2ssCj4gKwkJCQkgICAgY29u
c3QgdTggKnBvcykKPiArewo+ICsJdG9rLT5wb3MgPSBwb3M7Cj4gKwl0b2stPmxlbiA9ICgoKHBv
c1swXSAmIE1FRElVTV9BVE9NX0xFTl9NQVNLKSA8PCA4KSB8IHBvc1sxXSkgKyAyOwo+ICsJdG9r
LT53aWR0aCA9IE9QQUxfV0lEVEhfTUVESVVNOwo+ICsKPiArCWlmIChwb3NbMF0gJiBNRURJVU1f
QVRPTV9CWVRFU1RSSU5HKQo+ICsJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfQllURVNU
UklORzsKPiArCWVsc2UgaWYgKHBvc1swXSAmIE1FRElVTV9BVE9NX1NJR05FRCkKPiArCQl0b2st
PnR5cGUgPSBPUEFMX0RUQV9UT0tFTklEX1NJTlQ7Cj4gKwllbHNlCj4gKwkJdG9rLT50eXBlID0g
T1BBTF9EVEFfVE9LRU5JRF9VSU5UOwo+ICsKPiArCXJldHVybiB0b2stPmxlbjsKPiArfQo+ICsK
PiArI2RlZmluZSBMT05HX0FUT01fSUQgKEJJVCg3KSB8IEJJVCg2KSB8IEJJVCg1KSkKPiArI2Rl
ZmluZSBMT05HX0FUT01fQllURVNUUklORyBCSVQoMSkKPiArI2RlZmluZSBMT05HX0FUT01fU0lH
TkVEIEJJVCgwKQo+ICtzdGF0aWMgc2l6ZV90IHJlc3BvbnNlX3BhcnNlX2xvbmcoc3RydWN0IG9w
YWxfcmVzcF90b2sgKnRvaywKPiArCQkJCSAgY29uc3QgdTggKnBvcykKPiArewo+ICsJdG9rLT5w
b3MgPSBwb3M7Cj4gKwl0b2stPmxlbiA9ICgocG9zWzFdIDw8IDE2KSB8IChwb3NbMl0gPDwgOCkg
fCBwb3NbM10pICsgNDsKPiArCXRvay0+d2lkdGggPSBPUEFMX1dJRFRIX0xPTkc7Cj4gKwo+ICsJ
aWYgKHBvc1swXSAmIExPTkdfQVRPTV9CWVRFU1RSSU5HKQo+ICsJCXRvay0+dHlwZSA9IE9QQUxf
RFRBX1RPS0VOSURfQllURVNUUklORzsKPiArCWVsc2UgaWYgKHBvc1swXSAmIExPTkdfQVRPTV9T
SUdORUQpCj4gKwkJdG9rLT50eXBlID0gT1BBTF9EVEFfVE9LRU5JRF9TSU5UOwo+ICsJZWxzZQo+
ICsJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfVUlOVDsKPiArCj4gKwlyZXR1cm4gdG9r
LT5sZW47Cj4gK30KPiArCj4gK3N0YXRpYyBzaXplX3QgcmVzcG9uc2VfcGFyc2VfdG9rZW4oc3Ry
dWN0IG9wYWxfcmVzcF90b2sgKnRvaywKPiArCQkJCSAgIGNvbnN0IHU4ICpwb3MpCj4gK3sKPiAr
CXRvay0+cG9zID0gcG9zOwo+ICsJdG9rLT5sZW4gPSAxOwo+ICsJdG9rLT50eXBlID0gT1BBTF9E
VEFfVE9LRU5JRF9UT0tFTjsKPiArCXRvay0+d2lkdGggPSBPUEFMX1dJRFRIX1RPS0VOOwo+ICsK
PiArCXJldHVybiB0b2stPmxlbjsKPiArfQo+ICsKPiArc3RhdGljIGludCByZXNwb25zZV9wYXJz
ZShjb25zdCB1OCAqYnVmLCBzaXplX3QgbGVuZ3RoLAo+ICsJCQkgIHN0cnVjdCBwYXJzZWRfcmVz
cCAqcmVzcCkKPiArewo+ICsJY29uc3Qgc3RydWN0IG9wYWxfaGVhZGVyICpoZHI7Cj4gKwlzdHJ1
Y3Qgb3BhbF9yZXNwX3RvayAqaXRlcjsKPiArCWludCByZXQsIG51bV9lbnRyaWVzID0gMDsKPiAr
CXUzMiBjcG9zID0gMCwgdG90YWw7Cj4gKwlzaXplX3QgdG9rZW5fbGVuZ3RoOwo+ICsJY29uc3Qg
dTggKnBvczsKPiArCj4gKwlpZiAoIWJ1ZikKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiArCj4gKwlp
ZiAoIXJlc3ApCj4gKwkJcmV0dXJuIC1FRkFVTFQ7Cj4gKwo+ICsJaGRyID0gKHN0cnVjdCBvcGFs
X2hlYWRlciAqKWJ1ZjsKPiArCXBvcyA9IGJ1ZjsKPiArCXBvcyArPSBzaXplb2YoKmhkcik7Cj4g
Kwo+ICsJcHJfZGVidWcoIlJlc3BvbnNlIHNpemU6IGNwOiAlZCwgcGt0OiAlZCwgc3VicGt0OiAl
ZFxuIiwKPiArCQkgYmUzMl90b19jcHUoaGRyLT5jcC5sZW5ndGgpLAo+ICsJCSBiZTMyX3RvX2Nw
dShoZHItPnBrdC5sZW5ndGgpLAo+ICsJCSBiZTMyX3RvX2NwdShoZHItPnN1YnBrdC5sZW5ndGgp
KTsKPiArCj4gKwlpZiAoKGhkci0+Y3AubGVuZ3RoID09IDApCj4gKwkgICAgfHwgKGhkci0+cGt0
Lmxlbmd0aCA9PSAwKQo+ICsJICAgIHx8IChoZHItPnN1YnBrdC5sZW5ndGggPT0gMCkpIHsKPiAr
CQlwcl9lcnIoIkJhZCBoZWFkZXIgbGVuZ3RoLiBjcDogJWQsIHBrdDogJWQsIHN1YnBrdDogJWRc
biIsCj4gKwkJICAgICAgIGJlMzJfdG9fY3B1KGhkci0+Y3AubGVuZ3RoKSwKPiArCQkgICAgICAg
YmUzMl90b19jcHUoaGRyLT5wa3QubGVuZ3RoKSwKPiArCQkgICAgICAgYmUzMl90b19jcHUoaGRy
LT5zdWJwa3QubGVuZ3RoKSk7Cj4gKwkJcHJpbnRfYnVmZmVyKHBvcywgc2l6ZW9mKCpoZHIpKTsK
PiArCQlyZXQgPSAtRUlOVkFMOwo+ICsJCWdvdG8gZXJyOwo+ICsJfQo+ICsKPiArCWlmIChwb3Mg
PiBidWYgKyBsZW5ndGgpIHsKPiArCQlyZXQgPSAtRUZBVUxUOwo+ICsJCWdvdG8gZXJyOwo+ICsJ
fQo+ICsKPiArCWl0ZXIgPSByZXNwLT50b2tzOwo+ICsJdG90YWwgPSBiZTMyX3RvX2NwdShoZHIt
PnN1YnBrdC5sZW5ndGgpOwo+ICsJcHJpbnRfYnVmZmVyKHBvcywgdG90YWwpOwo+ICsJd2hpbGUg
KGNwb3MgPCB0b3RhbCkgewo+ICsJCWlmICghKHBvc1swXSAmIDB4ODApKSAvKiB0aW55IGF0b20g
Ki8KPiArCQkJdG9rZW5fbGVuZ3RoID0gcmVzcG9uc2VfcGFyc2VfdGlueShpdGVyLCBwb3MpOwo+
ICsJCWVsc2UgaWYgKCEocG9zWzBdICYgMHg0MCkpIC8qIHNob3J0IGF0b20gKi8KPiArCQkJdG9r
ZW5fbGVuZ3RoID0gcmVzcG9uc2VfcGFyc2Vfc2hvcnQoaXRlciwgcG9zKTsKPiArCQllbHNlIGlm
ICghKHBvc1swXSAmIDB4MjApKSAvKiBtZWRpdW0gYXRvbSAqLwo+ICsJCQl0b2tlbl9sZW5ndGgg
PSByZXNwb25zZV9wYXJzZV9tZWRpdW0oaXRlciwgcG9zKTsKPiArCQllbHNlIGlmICghKHBvc1sw
XSAmIDB4MTApKSAvKiBsb25nIGF0b20gKi8KPiArCQkJdG9rZW5fbGVuZ3RoID0gcmVzcG9uc2Vf
cGFyc2VfbG9uZyhpdGVyLCBwb3MpOwo+ICsJCWVsc2UgLyogVE9LRU4gKi8KPiArCQkJdG9rZW5f
bGVuZ3RoID0gcmVzcG9uc2VfcGFyc2VfdG9rZW4oaXRlciwgcG9zKTsKPiArCj4gKwkJcG9zICs9
IHRva2VuX2xlbmd0aDsKPiArCQljcG9zICs9IHRva2VuX2xlbmd0aDsKPiArCQlpdGVyKys7Cj4g
KwkJbnVtX2VudHJpZXMrKzsKPiArCX0KPiArCj4gKwlpZiAobnVtX2VudHJpZXMgPT0gMCkgewo+
ICsJCXByX2VycigiQ291bGRuJ3QgcGFyc2UgcmVzcG9uc2UuXG4iKTsKPiArCQlyZXQgPSAtRUlO
VkFMOwo+ICsJCWdvdG8gZXJyOwo+ICsJfQo+ICsJcmVzcC0+bnVtID0gbnVtX2VudHJpZXM7Cj4g
Kwo+ICsJcmV0dXJuIDA7Cj4gK2VycjoKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRp
YyBzaXplX3QgcmVzcG9uc2VfZ2V0X3N0cmluZyhjb25zdCBzdHJ1Y3QgcGFyc2VkX3Jlc3AgKnJl
c3AsIGludCBuLAo+ICsJCQkJICBjb25zdCBjaGFyICoqc3RvcmUpCj4gK3sKPiArCSpzdG9yZSA9
IE5VTEw7Cj4gKwlpZiAoIXJlc3ApIHsKPiArCQlwcl9lcnIoIlJlc3BvbnNlIGlzIE5VTExcbiIp
Owo+ICsJCXJldHVybiAwOwo+ICsJfQo+ICsKPiArCWlmIChuID4gcmVzcC0+bnVtKSB7Cj4gKwkJ
cHJfZXJyKCJSZXNwb25zZSBoYXMgJWQgdG9rZW5zLiBDYW4ndCBhY2Nlc3MgJWRcbiIsCj4gKwkJ
ICAgICAgIHJlc3AtPm51bSwgbik7Cj4gKwkJcmV0dXJuIDA7Cj4gKwl9Cj4gKwo+ICsJaWYgKHJl
c3AtPnRva3Nbbl0udHlwZSAhPSBPUEFMX0RUQV9UT0tFTklEX0JZVEVTVFJJTkcpIHsKPiArCQlw
cl9lcnIoIlRva2VuIGlzIG5vdCBhIGJ5dGUgc3RyaW5nIVxuIik7Cj4gKwkJcmV0dXJuIDA7Cj4g
Kwl9Cj4gKwo+ICsJKnN0b3JlID0gcmVzcC0+dG9rc1tuXS5wb3MgKyAxOwo+ICsJcmV0dXJuIHJl
c3AtPnRva3Nbbl0ubGVuIC0gMTsKPiArfQo+ICsKPiArc3RhdGljIHU2NCByZXNwb25zZV9nZXRf
dTY0KGNvbnN0IHN0cnVjdCBwYXJzZWRfcmVzcCAqcmVzcCwgaW50IG4pCj4gK3sKPiArCWlmICgh
cmVzcCkgewo+ICsJCXByX2VycigiUmVzcG9uc2UgaXMgTlVMTFxuIik7Cj4gKwkJcmV0dXJuIDA7
Cj4gKwl9Cj4gKwo+ICsJaWYgKG4gPiByZXNwLT5udW0pIHsKPiArCQlwcl9lcnIoIlJlc3BvbnNl
IGhhcyAlZCB0b2tlbnMuIENhbid0IGFjY2VzcyAlZFxuIiwKPiArCQkgICAgICAgcmVzcC0+bnVt
LCBuKTsKPiArCQlyZXR1cm4gMDsKPiArCX0KPiArCj4gKwlpZiAocmVzcC0+dG9rc1tuXS50eXBl
ICE9IE9QQUxfRFRBX1RPS0VOSURfVUlOVCkgewo+ICsJCXByX2VycigiVG9rZW4gaXMgbm90IHVu
c2lnbmVkIGl0OiAlZFxuIiwKPiArCQkgICAgICAgcmVzcC0+dG9rc1tuXS50eXBlKTsKPiArCQly
ZXR1cm4gMDsKPiArCX0KPiArCj4gKwlpZiAoISgocmVzcC0+dG9rc1tuXS53aWR0aCA9PSBPUEFM
X1dJRFRIX1RJTlkpIHx8Cj4gKwkgICAgICAocmVzcC0+dG9rc1tuXS53aWR0aCA9PSBPUEFMX1dJ
RFRIX1NIT1JUKSkpIHsKPiArCQlwcl9lcnIoIkF0b20gaXMgbm90IHNob3J0IG9yIHRpbnk6ICVk
XG4iLAo+ICsJCSAgICAgICByZXNwLT50b2tzW25dLndpZHRoKTsKPiArCQlyZXR1cm4gMDsKPiAr
CX0KPiArCj4gKwlyZXR1cm4gcmVzcC0+dG9rc1tuXS5zdG9yZWQudTsKPiArfQo+ICsKPiArc3Rh
dGljIHU4IHJlc3BvbnNlX3N0YXR1cyhjb25zdCBzdHJ1Y3QgcGFyc2VkX3Jlc3AgKnJlc3ApCj4g
K3sKPiArCWlmICgodG9rZW5fdHlwZShyZXNwLCAwKSA9PSBPUEFMX0RUQV9UT0tFTklEX1RPS0VO
KQo+ICsJICAgICYmIChyZXNwb25zZV9nZXRfdG9rZW4ocmVzcCwgMCkgPT0gT1BBTF9FTkRPRlNF
U1NJT04pKSB7Cj4gKwkJcmV0dXJuIDA7Cj4gKwl9Cj4gKwo+ICsJaWYgKHJlc3AtPm51bSA8IDUp
Cj4gKwkJcmV0dXJuIERUQUVSUk9SX05PX01FVEhPRF9TVEFUVVM7Cj4gKwo+ICsJaWYgKCh0b2tl
bl90eXBlKHJlc3AsIHJlc3AtPm51bSAtIDEpICE9IE9QQUxfRFRBX1RPS0VOSURfVE9LRU4pIHx8
Cj4gKwkgICAgKHRva2VuX3R5cGUocmVzcCwgcmVzcC0+bnVtIC0gNSkgIT0gT1BBTF9EVEFfVE9L
RU5JRF9UT0tFTikgfHwKPiArCSAgICAocmVzcG9uc2VfZ2V0X3Rva2VuKHJlc3AsIHJlc3AtPm51
bSAtIDEpICE9IE9QQUxfRU5ETElTVCkgfHwKPiArCSAgICAocmVzcG9uc2VfZ2V0X3Rva2VuKHJl
c3AsIHJlc3AtPm51bSAtIDUpICE9IE9QQUxfU1RBUlRMSVNUKSkKPiArCQlyZXR1cm4gRFRBRVJS
T1JfTk9fTUVUSE9EX1NUQVRVUzsKPiArCj4gKwlyZXR1cm4gcmVzcG9uc2VfZ2V0X3U2NChyZXNw
LCByZXNwLT5udW0gLSA0KTsKPiArfQo+ICsKPiArLyogUGFyc2VzIGFuZCBjaGVja3MgZm9yIGVy
cm9ycyAqLwo+ICtzdGF0aWMgaW50IHBhcnNlX2FuZF9jaGVja19zdGF0dXMoc3RydWN0IG9wYWxf
ZGV2ICpkZXYpCj4gK3sKPiArCXN0cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsJaW50IGVycm9yOwo+
ICsKPiArCWNtZCA9ICZkZXYtPmNtZDsKPiArCXByaW50X2J1ZmZlcihjbWQtPmNtZCwgY21kLT5w
b3MpOwo+ICsKPiArCWVycm9yID0gcmVzcG9uc2VfcGFyc2UoY21kLT5yZXNwLCBJT19CVUZGRVJf
TEVOR1RILCAmZGV2LT5wYXJzZWQpOwo+ICsJaWYgKGVycm9yKSB7Cj4gKwkJcHJfZXJyKCIlczog
Q291bGRuJ3QgcGFyc2UgcmVzcG9uc2UuXG4iLCBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJZ290byBl
cnJfcmV0dXJuOwo+ICsJfQo+ICsKPiArCWVycm9yID0gcmVzcG9uc2Vfc3RhdHVzKCZkZXYtPnBh
cnNlZCk7Cj4gKwlpZiAoZXJyb3IpCj4gKwkJcHJfZXJyKCIlczogUmVzcG9uc2UgU3RhdHVzOiAl
ZFxuIiwgZGV2LT5kaXNrX25hbWUsCj4gKwkJICAgICAgIGVycm9yKTsKPiArCj4gKyBlcnJfcmV0
dXJuOgo+ICsJcmV0dXJuIGVycm9yOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBjbGVhcl9vcGFs
X2NtZChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCkKPiArewo+ICsJY21kLT5wb3MgPSBzaXplb2Yoc3Ry
dWN0IG9wYWxfaGVhZGVyKTsKPiArCW1lbXNldChjbWQtPmNtZCwgMCwgSU9fQlVGRkVSX0xFTkdU
SCk7Cj4gKwljbWQtPmNiID0gTlVMTDsKPiArCWNtZC0+Y2JfZGF0YSA9IE5VTEw7Cj4gK30KPiAr
Cj4gK3N0YXRpYyB2b2lkIHN0YXJ0X29wYWxfc2Vzc2lvbl9jb250KGludCBlcnJvciwgdm9pZCAq
ZGF0YSkKPiArewo+ICsJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOwo+ICsJdTMyIEhTTiwg
VFNOOwo+ICsKPiArCWlmIChlcnJvcikKPiArCQlnb3RvIGVycl9yZXR1cm47Cj4gKwo+ICsJZXJy
b3IgPSBwYXJzZV9hbmRfY2hlY2tfc3RhdHVzKGRldik7Cj4gKwlpZiAoZXJyb3IpCj4gKwkJZ290
byBlcnJfcmV0dXJuOwo+ICsKPiArCUhTTiA9IHJlc3BvbnNlX2dldF91NjQoJmRldi0+cGFyc2Vk
LCA0KTsKPiArCVRTTiA9IHJlc3BvbnNlX2dldF91NjQoJmRldi0+cGFyc2VkLCA1KTsKPiArCj4g
KwlpZiAoSFNOID09IDAgJiYgVFNOID09IDApIHsKPiArCQlwcl9lcnIoIiVzOiBDb3VsZG4ndCBh
dXRoZW50aWNhdGUgc2Vzc2lvblxuIiwgZGV2LT5kaXNrX25hbWUpOwo+ICsJCWVycm9yID0gLUVQ
RVJNOwo+ICsJCWdvdG8gZXJyX3JldHVybjsKPiArCX0KPiArCj4gKwlkZXYtPkhTTiA9IEhTTjsK
PiArCWRldi0+VFNOID0gVFNOOwo+ICsKPiArZXJyX3JldHVybjoKPiArCWlmIChkZXYtPm9wZXJf
Y2IpCj4gKwkJZGV2LT5vcGVyX2NiKGVycm9yLCBkZXYpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50
IGdldF9vcGFsX2tleShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJc3RydWN0IGtleSAq
dWtleSA9IE5VTEw7Cj4gKwljb25zdCB1OCAqdG1wa2V5ID0gTlVMTDsKPiArCXNpemVfdCB0bXBs
ZW47Cj4gKwlpbnQgcmV0ID0gMDsKPiArCj4gKwlpZiAoZGV2LT5rZXlfdHlwZSA9PSBPUEFMX0tF
WV9QTEFJTikgewo+ICsJCXRtcGtleSA9IGRldi0+a2V5X25hbWU7Cj4gKwkJdG1wbGVuID0gZGV2
LT5rZXlfbmFtZV9sZW47Cj4gKwl9IGVsc2UgaWYgKGRldi0+a2V5X3R5cGUgPT0gT1BBTF9LRVlf
S0VZUklORykgewo+ICsJCXVrZXkgPSByZXF1ZXN0X3VzZXJfa2V5KGRldi0+a2V5X25hbWUsICZ0
bXBrZXksICZ0bXBsZW4pOwo+ICsJCWlmIChJU19FUlIodWtleSkpIHsKPiArCQkJcHJfZXJyKCIl
czogQ2FuJ3QgcmV0cmlldmUga2V5OiAlbGRcbiIsIGRldi0+ZGlza19uYW1lLAo+ICsJCQkgICAg
ICAgUFRSX0VSUih1a2V5KSk7Cj4gKwkJCXJldHVybiBQVFJfRVJSKHVrZXkpOwo+ICsJCX0KPiAr
CX0gZWxzZSB7Cj4gKwkJcHJfZXJyKCJSZXF1ZXN0ZWQgaW52YWxpZCBrZXkgdHlwZTogJWRcbiIs
IGRldi0+a2V5X3R5cGUpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCWlmICh0
bXBsZW4gPiBPUEFMX0tFWV9NQVgpIHsKPiArCQlwcl9lcnIoIlJlcXVlc3RlZCBrZXkgd2l0aCBp
bnZhbGlkIHNpemU6ICV6ZFxuIiwgdG1wbGVuKTsKPiArCQlyZXQgPSAtRUlOVkFMOwo+ICsJCWdv
dG8gZXJyX2V4aXQ7Cj4gKwl9Cj4gKwo+ICsJZGV2LT5rZXlfbGVuID0gdG1wbGVuOwo+ICsJaWYg
KCFtZW1jcHkoZGV2LT5rZXksIHRtcGtleSwgdG1wbGVuKSkgewo+ICsJCXByX2VycigiRXJyb3Ig
d2hlbiBjb3B5aW5nIGtleSIpOwo+ICsJCXJldCA9IC1FRkFVTFQ7Cj4gKwkJZ290byBlcnJfZXhp
dDsKPiArCX0KPiArCj4gK2Vycl9leGl0Ogo+ICsJa2V5X3B1dCh1a2V5KTsKPiArCj4gKwlyZXR1
cm4gMDsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgY2xlYW5fb3BhbF9rZXkoc3RydWN0IG9wYWxf
ZGV2ICpkZXYpCj4gK3sKPiArCW1lbXNldChkZXYtPmtleSwgMCwgT1BBTF9LRVlfTUFYKTsKPiAr
CWRldi0+a2V5X2xlbiA9IDA7Cj4gK30KPiArCj4gK3N0YXRpYyBpbmxpbmUgdm9pZCBjbGVhbl9m
dW5jdGlvbl9kYXRhKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwkJZGV2LT5mdW5jX2Rh
dGEgPSBOVUxMOwo+ICsJCWRldi0+bnVtX2Z1bmNfZGF0YSA9IDA7Cj4gK30KPiArCj4gKy8qIFRo
aXMgaXMgYSBnZW5lcmljIGNvbnRpbnVlIGZuLgo+ICsgKiBXZSB1c2UgdGhpcyB3aGVuIHdlIGRv
bid0IGNhcmUgYWJvdXQgdGhlIHJlc3BvbnNlIGRhdGEKPiArICogYW5kIHNpbXBseSB3YW50IHRv
IGNoZWNrIHRoZSBzdGF0dXMgYW5kIGNvbnRpbnVlLgo+ICsgKi8KPiArc3RhdGljIHZvaWQgZ2Vu
ZXJpY19jb250KGludCBlcnJvciwgdm9pZCAqZGF0YSkKPiArewo+ICsJc3RydWN0IG9wYWxfZGV2
ICpkZXYgPSBkYXRhOwo+ICsKPiArCWlmIChlcnJvcikKPiArCQlnb3RvIGVycl9yZXR1cm47Cj4g
Kwo+ICsJZXJyb3IgPSBwYXJzZV9hbmRfY2hlY2tfc3RhdHVzKGRldik7Cj4gKwo+ICsgZXJyX3Jl
dHVybjoKPiArCWlmIChkZXYtPm9wZXJfY2IpCj4gKwkJZGV2LT5vcGVyX2NiKGVycm9yLCBkZXYp
Owo+ICt9CgpIb3cgYWJvdXQ6CgpzdGF0aWMgdm9pZCBnZW5lcmljX2NvbnQoaW50IGVycm9yLCB2
b2lkICpkYXRhKQp7CglzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CgoJaWYgKCFlcnJvcikK
CQllcnJvciA9IHBhcnNlX2FuZF9jaGVja19zdGF0dXMoZGV2KTsKCglpZiAoZGV2LT5vcGVyX2Ni
KQoJCWRldi0+b3Blcl9jYihlcnJvciwgZGV2KTsKfQoKPiArCj4gK3N0YXRpYyB2b2lkIGVuZF9z
ZXNzaW9uX2NvbnQoaW50IGVycm9yLCB2b2lkICpkYXRhKQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9k
ZXYgKmRldiA9IGRhdGE7Cj4gKwo+ICsJZGV2LT5IU04gPSAwOwo+ICsJZGV2LT5UU04gPSAwOwo+
ICsJZ2VuZXJpY19jb250KGVycm9yLCBkYXRhKTsKPiArfQo+ICsKPiArc3RhdGljIGludCBmaW5h
bGl6ZV9hbmRfc2VuZChzdHJ1Y3Qgb3BhbF9kZXYgKmRldiwgc3RydWN0IG9wYWxfY21kICpjbWQs
Cj4gKwkJCSAgICAgc2VjX2NiIGNvbnQpCj4gK3sKPiArCWludCByZXQ7Cj4gKwo+ICsJcmV0ID0g
Y21kX2ZpbmFsaXplKGNtZCwgZGV2LT5IU04sIGRldi0+VFNOKTsKPiArCWlmIChyZXQpIHsKPiAr
CQlwcl9lcnIoIiVzOiBFcnJvciBmaW5hbGl6aW5nIGNvbW1hbmQgYnVmZmVyOiAlZFxuIiwKPiAr
CQkgICAgICAgZGV2LT5kaXNrX25hbWUsIHJldCk7Cj4gKwkJcmV0dXJuIHJldDsKPiArCX0KPiAr
Cj4gKwlwcmludF9idWZmZXIoY21kLT5jbWQsIGNtZC0+cG9zKTsKPiArCj4gKwlyZXQgPSBvcGFs
X3NlbmRfcmVjdihkZXYsIGNvbnQsIGRldik7Cj4gKwlpZiAocmV0KQo+ICsJCXByX2VycigiJXM6
IEVycm9yIHJ1bm5pbmcgY29tbWFuZDogJWRcbiIsCj4gKwkJICAgICAgIGRldi0+ZGlza19uYW1l
LCByZXQpOwo+ICsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgd2FpdF9m
b3JfY21kX2NvbXBsZXRpb24oc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbikKPiAr
ewo+ICsJd2FpdF9mb3JfY29tcGxldGlvbl9pbnRlcnJ1cHRpYmxlKCZjb21wbGV0aW9uLT5jbWRf
Y29tcGxldGlvbik7Cj4gKwlyZXR1cm4gY29tcGxldGlvbi0+Y29tcGxldGlvbl9zdGF0dXM7Cj4g
K30KPiArCj4gK3N0YXRpYyBpbnQgZ2VuX2tleShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+
ICsJY29uc3QgdTggKm1ldGhvZDsKPiArCXU4IHVpZFtPUEFMX1VJRF9MRU5HVEhdOwo+ICsJc3Ry
dWN0IG9wYWxfY21kICpjbWQ7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWNtZCA9ICZkZXYtPmNtZDsK
PiArCWNsZWFyX29wYWxfY21kKGNtZCk7Cj4gKwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsK
PiArCj4gKwltZW1jcHkodWlkLCBkZXYtPnByZXZfZGF0YSwgbWluKHNpemVvZih1aWQpLCBkZXYt
PnByZXZfZF9sZW4pKTsKPiArCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9HRU5LRVldOwo+ICsJ
a2ZyZWUoZGV2LT5wcmV2X2RhdGEpOwo+ICsJZGV2LT5wcmV2X2RhdGEgPSBOVUxMOwo+ICsKPiAr
CXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMgMmMiLAo+ICsJCQkJICAgIE9Q
QUxfQ0FMTCwKPiArCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJCSAgICBtZXRo
b2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4g
KwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIl
czogRXJyb3IgYnVpbGRpbmcgZ2VuIGtleSBjb21tYW5kXG4iLAo+ICsJCSAgICAgICBkZXYtPmRp
c2tfbmFtZSk7Cj4gKwkJcmV0dXJuIHJldDsKPiArCX0KPiArCj4gKwlyZXR1cm4gZmluYWxpemVf
YW5kX3NlbmQoZGV2LCBjbWQsIGdlbmVyaWNfY29udCk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lk
IGdldF9hY3RpdmVfa2V5X2NvbnQoaW50IGVycm9yLCB2b2lkICpkYXRhKQo+ICt7Cj4gKwlzdHJ1
Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7Cj4gKwljb25zdCBjaGFyICphY3RpdmVrZXk7Cj4gKwlz
aXplX3Qga2V5bGVuOwo+ICsKPiArCWlmIChlcnJvcikKPiArCQlnb3RvIGVycl9yZXR1cm47Cj4g
Kwo+ICsJZXJyb3IgPSBwYXJzZV9hbmRfY2hlY2tfc3RhdHVzKGRldik7Cj4gKwlpZiAoZXJyb3Ip
Cj4gKwkJZ290byBlcnJfcmV0dXJuOwo+ICsJa2V5bGVuID0gcmVzcG9uc2VfZ2V0X3N0cmluZygm
ZGV2LT5wYXJzZWQsIDQsICZhY3RpdmVrZXkpOwo+ICsJaWYgKCFhY3RpdmVrZXkpIHsKPiArCQlw
cl9lcnIoIiVzOiBDb3VsZG4ndCBleHRyYWN0IHRoZSBBY3RpdmVrZXkgZnJvbSB0aGUgcmVzcG9u
c2VcbiIsCj4gKwkJICAgICAgIF9fZnVuY19fKTsKPiArCQllcnJvciA9IDB4MEE7Cj4gKwkJZ290
byBlcnJfcmV0dXJuOwo+ICsJfQo+ICsJZGV2LT5wcmV2X2RhdGEgPSBrbWVtZHVwKGFjdGl2ZWtl
eSwga2V5bGVuLCBHRlBfS0VSTkVMKTsKPiArCj4gKwlpZiAoIWRldi0+cHJldl9kYXRhKQo+ICsJ
CWVycm9yID0gLUVOT01FTTsKPiArCj4gKwlkZXYtPnByZXZfZF9sZW4gPSBrZXlsZW47Cj4gKwo+
ICtlcnJfcmV0dXJuOgo+ICsJaWYgKGRldi0+b3Blcl9jYikKPiArCQlkZXYtPm9wZXJfY2IoZXJy
b3IsIGRldik7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgZ2V0X2FjdGl2ZV9rZXkoc3RydWN0IG9w
YWxfZGV2ICpkZXYpCj4gK3sKPiArCWNvbnN0IHU4ICptZXRob2Q7Cj4gKwl1OCB1aWRbT1BBTF9V
SURfTEVOR1RIXTsKPiArCXN0cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsJaW50IHJldDsKPiArCj4g
KwljbWQgPSAmZGV2LT5jbWQ7Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+ICsJc2V0X2NvbUlE
KGNtZCwgZGV2LT5jb21JRCk7Cj4gKwo+ICsJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX0dFVF07
Cj4gKwo+ICsJcmV0ID0gYnVpbGRfbG9ja2luZ19yYW5nZSh1aWQsIHNpemVvZih1aWQpLCBkZXYt
PmxyKTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogQ2FuJ3QgYnVpbGQgbG9j
a2luZyByYW5nZVxuIiwgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJ
fQo+ICsKPiArCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMgNmMgNGMgMmMi
LAo+ICsJCQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwK
PiArCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJCQkgICAgT1BB
TF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9T
VEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIHN0YXJ0Q2xvdW1uICov
Cj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMTAsIC8qIEFjdGl2ZUtleSAqLwo+ICsJCQkJICAg
IE9QQUxfRU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAg
T1BBTF9USU5ZX1VJTlRfMDQsIC8qIGVuZENvbHVtbiAqLwo+ICsJCQkJICAgIE9QQUxfVElOWV9V
SU5UXzEwLCAvKiBBY3RpdmVLZXkgKi8KPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwo+ICsJ
CQkJICAgIE9QQUxfRU5ETElTVCwKPiArCQkJCSAgICBPUEFMX0VORExJU1QpOwo+ICsJaWYgKHJl
dCA8IDApIHsKPiArCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBnZXQgYWN0aXZlIGtleSBj
b21tYW5kXG4iLAo+ICsJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJcmV0dXJuIHJldDsK
PiArCX0KPiArCj4gKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdldF9hY3Rp
dmVfa2V5X2NvbnQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNldHVwX2xvY2tpbmdfcmFuZ2Uo
c3RydWN0IG9wYWxfZGV2ICpkZXYpCj4gK3sKPiArCWNvbnN0IHU4ICptZXRob2Q7Cj4gKwl1OCB1
aWRbT1BBTF9VSURfTEVOR1RIXTsKPiArCXN0cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsJc3RydWN0
IG9wYWxfdXNlcl9scl9zZXR1cCAqc2V0dXA7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWNtZCA9ICZk
ZXYtPmNtZDsKPiArCWNsZWFyX29wYWxfY21kKGNtZCk7Cj4gKwlzZXRfY29tSUQoY21kLCBkZXYt
PmNvbUlEKTsKPiArCj4gKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfU0VUXTsKPiArCXJldCA9
IGJ1aWxkX2xvY2tpbmdfcmFuZ2UodWlkLCBzaXplb2YodWlkKSwgZGV2LT5scik7Cj4gKwlpZiAo
cmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgcmFuZ2VcbiIs
IGRldi0+ZGlza19uYW1lKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0KPiArCXNldHVwID0g
ZGV2LT5mdW5jX2RhdGFbZGV2LT5zdGF0ZSAtIDFdOwo+ICsKPiArCXJldCA9IHRlc3RfYW5kX2Fk
ZF90b2tlbl92YShjbWQsICJjMnMgIDRjIDJjdWMgMmN1YyAyY3VjIDJjdSA0YyIsCj4gKwkJCQkg
ICAgT1BBTF9DQUxMLAo+ICsJCQkJICAgIHVpZCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAg
IG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTElT
VCwKPiArCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1ZBTFVFUywKPiAr
CQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4g
KwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIFJhbmdlIFN0YXJ0ICovCj4gKwkJCQkgICAg
c2V0dXAtPnJhbmdlX3N0YXJ0LAo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCj4gKwkJCQkg
ICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDQsIC8qIFJhbmdl
IExlbmd0aCAqLwo+ICsJCQkJICAgIHNldHVwLT5yYW5nZV9sZW5ndGgsCj4gKwkJCQkgICAgT1BB
TF9FTkROQU1FLAo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFM
X1RJTllfVUlOVF8wNSwgLyogUmVhZExvY2tFbmFibGVkICovCj4gKwkJCQkgICAgISFzZXR1cC0+
UkxFLAo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5B
TUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDYsIC8qIFdyaXRlTG9ja0VuYWJsZWQgKi8K
PiArCQkJCSAgICAhIXNldHVwLT5XTEUsCj4gKwo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiAr
CQkJCSAgICBPUEFMX0VORExJU1QsCj4gKwkJCQkgICAgT1BBTF9FTkROQU1FLAo+ICsJCQkJICAg
IE9QQUxfRU5ETElTVCk7Cj4gKwlpZiAocmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9y
IGJ1aWxkaW5nIFNldHVwIExvY2tpbmcgcmFuZ2UgY29tbWFuZC5cbiIsCj4gKwkJICAgICAgIGRl
di0+ZGlza19uYW1lKTsKPiArCQlyZXR1cm4gcmV0Owo+ICsKPiArCX0KPiArCj4gKwlyZXR1cm4g
ZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdlbmVyaWNfY29udCk7Cj4gK30KPiArCj4gK3N0
YXRpYyBpbnQgc3RhcnRfYWRtaW5zcF9vcGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2ICpkZXYs
Cj4gKwkJCQkgICAgICBlbnVtIE9QQUxfVUlEIGF1dGgsCj4gKwkJCQkgICAgICBjb25zdCBjaGFy
ICprZXksCj4gKwkJCQkgICAgICB1OCBrZXlfbGVuKQo+ICt7Cj4gKwljb25zdCB1OCAqbWV0aG9k
LCAqc211aWQsICphZG1pbl9zcCwgKmhzYTsKPiArCXN0cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsJ
dTMyIEhTTjsKPiArCWludCByZXQ7Cj4gKwo+ICsJaWYgKGtleSA9PSBOVUxMICYmIGF1dGggIT0g
T1BBTF9BTllCT0RZX1VJRCkgewo+ICsJCXByX2VycigiJXM6IEF0dGVtcHRlZCB0byBvcGVuIEFE
TUlOX1NQIFNlc3Npb24gd2l0aG91dCBhIEhvc3QiIFwKPiArCQkgICAgICAgIkNoYWxsZW5nZSwg
YW5kIG5vdCBhcyB0aGUgQW55Ym9keSBVSURcbiIsIF9fZnVuY19fKTsKPiArCQlyZXR1cm4gMTsK
PiArCX0KPiArCj4gKwljbWQgPSAmZGV2LT5jbWQ7Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+
ICsKPiArCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOwo+ICsJSFNOID0gMHg0MTsKPiArCj4g
KwlzbXVpZCA9IE9QQUxVSURbT1BBTF9TTVVJRF9VSURdOwo+ICsJbWV0aG9kID0gT1BBTE1FVEhP
RFtPUEFMX1NUQVJUU0VTU0lPTl07Cj4gKwlhZG1pbl9zcCA9IE9QQUxVSURbT1BBTF9BRE1JTlNQ
X1VJRF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyBjdXNj
IiwKPiArCQkJCSAgICBPUEFMX0NBTEwsCj4gKwkJCQkgICAgc211aWQsIE9QQUxfVUlEX0xFTkdU
SCwKPiArCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCQkJCSAgICBPUEFM
X1NUQVJUTElTVCwKPiArCQkJCSAgICBIU04sCj4gKwkJCQkgICAgYWRtaW5fc3AsIE9QQUxfVUlE
X0xFTkdUSCwKPiArCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMSk7Cj4gKwlpZiAocmV0IDwgMCkg
ewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIHN0YXJ0IGFkbWluc3Agc2Vzc2lvbiBj
b21tYW5kLlxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiByZXQ7
Cj4gKwl9Cj4gKwo+ICsJc3dpdGNoIChhdXRoKSB7Cj4gKwljYXNlIE9QQUxfQU5ZQk9EWV9VSUQ6
Cj4gKwkJLyogbm90aGluZyBsZWZ0IHRvIGRvIGZvciBhbnlib2R5LCBqdXN0IGVuZCBhbmQgZmlu
YWxpemUgKi8KPiArCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYyIsCj4gKwkJ
CQkJICAgIE9QQUxfRU5ETElTVCk7Cj4gKwkJYnJlYWs7Cj4gKwljYXNlIE9QQUxfU0lEX1VJRDoK
PiArCQloc2EgPSBPUEFMVUlEW09QQUxfU0lEX1VJRF07Cj4gKwkJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgIjJjIHMgM2MgcyAyYyIsCj4gKwkJCQkJICAgIE9QQUxfU1RBUlROQU1F
LAo+ICsJCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMCwgLyogSG9zdENoYWxsZW5nZSAqLwo+ICsJ
CQkJCSAgICBrZXksIGtleV9sZW4sCj4gKwkJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCQkJCQkg
ICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAzLCAvKiBIb3N0
U2lnbkF1dGggKi8KPiArCQkJCQkgICAgaHNhLCBPUEFMX1VJRF9MRU5HVEgsCj4gKwkJCQkJICAg
IE9QQUxfRU5ETkFNRSwKPiArCQkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCQlicmVhazsKPiAr
CWRlZmF1bHQ6Cj4gKwkJcHJfZXJyKCJDYW5ub3Qgc3RhcnQgQWRtaW4gU1Agc2Vzc2lvbiB3aXRo
IGF1dGggJWRcbiIsIGF1dGgpOwo+ICsJCXJldHVybiAxOwo+ICsJfQo+ICsKPiArCWlmIChyZXQg
PCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgc3RhcnQgYWRtaW5zcCBzZXNz
aW9uIGNvbW1hbmQuXG4iLAo+ICsJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJcmV0dXJu
IHJldDsKPiArCX0KPiArCj4gKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIHN0
YXJ0X29wYWxfc2Vzc2lvbl9jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBzdGFydF9hbnli
b2R5QVNQX29wYWxfc2Vzc2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJcmV0dXJu
IHN0YXJ0X2FkbWluc3Bfb3BhbF9zZXNzaW9uKGRldiwgT1BBTF9BTllCT0RZX1VJRCwgTlVMTCwg
MCk7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgc3RhcnRfU0lEQVNQX29wYWxfc2Vzc2lvbihzdHJ1
Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJaW50IHJldDsKPiArCWNvbnN0IHU4ICprZXkgPSBk
ZXYtPnByZXZfZGF0YTsKPiArCj4gKwlpZiAoIWtleSkKPiArCQlyZXQgPSBzdGFydF9hZG1pbnNw
X29wYWxfc2Vzc2lvbihkZXYsIE9QQUxfU0lEX1VJRCwgZGV2LT5rZXksCj4gKwkJCQkJCSBkZXYt
PmtleV9sZW4pOwo+ICsJZWxzZSB7Cj4gKwkJcmV0ID0gc3RhcnRfYWRtaW5zcF9vcGFsX3Nlc3Np
b24oZGV2LCBPUEFMX1NJRF9VSUQsIGtleSwKPiArCQkJCQkJIGRldi0+cHJldl9kX2xlbik7Cj4g
KwkJa2ZyZWUoa2V5KTsKPiArCQlkZXYtPnByZXZfZGF0YSA9IE5VTEw7Cj4gKwl9Cj4gKwlyZXR1
cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHN0YXJ0X2xvY2tpbmdzcF9vcGFsX3Nlc3Np
b24oc3RydWN0IG9wYWxfZGV2ICpkZXYsCj4gKwkJCQkJZW51bSBPUEFMX1VJRCBhdXRoLCBjb25z
dCB1OCAqa2V5LAo+ICsJCQkJCXU4IGtleV9sZW4pCj4gK3sKPiArCj4gKwljb25zdCB1OCAqbWV0
aG9kLCAqc211aWQsICpsb2NraW5nX3NwLCAqaHNhOwo+ICsJc3RydWN0IG9wYWxfY21kICpjbWQ7
Cj4gKwlzaXplX3Qga2xlbiA9IGtleV9sZW47Cj4gKwl1MzIgSFNOOwo+ICsJaW50IHJldDsKPiAr
Cj4gKwlpZiAoa2V5ID09IE5VTEwpIHsKPiArCQlwcl9lcnIoIkNhbm5vdCBzdGFydCBMb2NraW5n
IFNQIHNlc3Npb24gd2l0aG91dCBhIGtleVxuIik7Cj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwl9
Cj4gKwo+ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCj4g
KwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsKPiArCUhTTiA9IDB4NDE7Cj4gKwo+ICsJc211
aWQgPSBPUEFMVUlEW09QQUxfU01VSURfVUlEXTsKPiArCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BB
TF9TVEFSVFNFU1NJT05dOwo+ICsJbG9ja2luZ19zcCA9IE9QQUxVSURbT1BBTF9MT0NLSU5HU1Bf
VUlEXTsKPiArCWhzYSA9IE9QQUxVSURbYXV0aF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgImMycyBjdXNjIDJjc2MgMmNzYyBjIiwKPiArCQkJCSAgICBPUEFMX0NB
TEwsCj4gKwkJCQkgICAgc211aWQsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJCSAgICBtZXRob2Qs
IE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJ
CQkgICAgSFNOLAo+ICsJCQkJICAgIGxvY2tpbmdfc3AsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJ
CSAgICBPUEFMX1RJTllfVUlOVF8wMSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4g
KwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDAsIC8qIEhvc3RDaGFsbGVuZ2UgKi8KPiArCQkJCSAg
ICBrZXksIGtsZW4sCj4gKwkJCQkgICAgT1BBTF9FTkROQU1FLAo+ICsKPiArCQkJCSAgICBPUEFM
X1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMywgLyogSG9zdCBTaWduIEF1
dGhvcml0eSAqLwo+ICsJCQkJICAgIGhzYSwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIE9Q
QUxfRU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCj4gKwlpZiAocmV0
IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIHN0YXJ0IGFkbWluc3Agc2Vz
c2lvbiBjb21tYW5kLlxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVy
biByZXQ7Cj4gKwl9Cj4gKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIHN0YXJ0
X29wYWxfc2Vzc2lvbl9jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGlubGluZSBpbnQgc3RhcnRf
YWRtaW4xTFNQX29wYWxfc2Vzc2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJcmV0
dXJuIHN0YXJ0X2xvY2tpbmdzcF9vcGFsX3Nlc3Npb24oZGV2LCBPUEFMX0FETUlOMV9VSUQsCj4g
KwkJCQkJICAgIGRldi0+a2V5LCBkZXYtPmtleV9sZW4pOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50
IHN0YXJ0X2F1dGhfb3BhbF9zZXNzaW9uKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwlj
b25zdCB1OCAqbWV0aG9kLCAqc211aWQsICpsb2NraW5nX3NwOwo+ICsJdTggbGtfdWxfdXNlcltP
UEFMX1VJRF9MRU5HVEhdOwo+ICsJc3RydWN0IG9wYWxfY21kICpjbWQ7Cj4gKwl1MzIgSFNOOwo+
ICsJaW50IHJldDsKPiArCXN0cnVjdCBvcGFsX3VzZXJfaW5mbyAqdWluZm87Cj4gKwo+ICsJY21k
ID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCj4gKwlzZXRfY29tSUQo
Y21kLCBkZXYtPmNvbUlEKTsKPiArCj4gKwlIU04gPSAweDQxOwpDYW4gd2UgI2RlZmluZSB0aGlz
OyBpdCdzIHVzZWQgYSBmZXcgb3RoZXIgcGxhY2VzIGFuZCBpcyBtYWdpY2t5Cgo+ICsKPiArCXVp
bmZvID0gZGV2LT5mdW5jX2RhdGFbZGV2LT5zdGF0ZSAtIDFdOwo+ICsKPiArCXNtdWlkID0gT1BB
TFVJRFtPUEFMX1NNVUlEX1VJRF07Cj4gKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfU1RBUlRT
RVNTSU9OXTsKPiArCWxvY2tpbmdfc3AgPSBPUEFMVUlEW09QQUxfTE9DS0lOR1NQX1VJRF07Cj4g
Kwo+ICsJaWYgKHVpbmZvLT5TVU0pIHsKPiArCQlyZXQgPSBidWlsZF9sb2NraW5nX3VzZXIobGtf
dWxfdXNlciwgc2l6ZW9mKGxrX3VsX3VzZXIpLAo+ICsJCQkJCSBkZXYtPmxyKTsKPiArCQlpZiAo
cmV0IDwgMCkgewo+ICsJCQlwcl9lcnIoIiVzOiBDYW4ndCBidWlsZCBsb2NraW5nIHVzZXJcbiIs
Cj4gKwkJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJCXJldHVybiByZXQ7Cj4gKwkJfQo+
ICsJfSBlbHNlIGlmICh1aW5mby0+d2hvICE9IE9QQUxfQURNSU4xICYmICF1aW5mby0+U1VNKSB7
Cj4gKwkJcmV0ID0gYnVpbGRfbG9ja2luZ191c2VyKGxrX3VsX3VzZXIsIHNpemVvZihsa191bF91
c2VyKSwKPiArCQkJCQkgdWluZm8tPndobyAtIDEpOwo+ICsJCWlmIChyZXQgPCAwKSB7Cj4gKwkJ
CXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgdXNlclxuIiwKPiArCQkJICAgICAgIGRl
di0+ZGlza19uYW1lKTsKPiArCQkJcmV0dXJuIHJldDsKPiArCQl9Cj4gKwl9IGVsc2UKPiArCQlt
ZW1jcHkobGtfdWxfdXNlciwgT1BBTFVJRFtPUEFMX0FETUlOMV9VSURdLCBPUEFMX1VJRF9MRU5H
VEgpOwo+ICsKPiArCj4gKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIGN1
czNjczNjIHMgMmMiLAo+ICsJCQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAgICBzbXVpZCwgT1BB
TF9VSURfTEVOR1RILAo+ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAo+ICsK
PiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICBIU04sCj4gKwkJCQkgICAgbG9j
a2luZ19zcCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAxLAo+
ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAwLAo+
ICsJCQkJICAgIGRldi0+a2V5LCBkZXYtPmtleV9sZW4sCj4gKwkJCQkgICAgT1BBTF9FTkROQU1F
LAo+ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAz
LAo+ICsKPiArCQkJCSAgICBsa191bF91c2VyLCBPUEFMX1VJRF9MRU5HVEgsCj4gKwo+ICsJCQkJ
ICAgIE9QQUxfRU5ETkFNRSwKPiArCQkJCSAgICBPUEFMX0VORExJU1QpOwo+ICsKPiArCWlmIChy
ZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgU1RBUlRTRVNTSU9OIGNv
bW1hbmQuXG4iLAo+ICsJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJcmV0dXJuIHJldDsK
PiArCX0KPiArCj4gKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIHN0YXJ0X29w
YWxfc2Vzc2lvbl9jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGludCByZXZlcnRfdHBlcihzdHJ1
Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJY29uc3QgdTggKm1ldGhvZCwgKnNtdWlkOwo+ICsJ
c3RydWN0IG9wYWxfY21kICpjbWQ7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWNtZCA9ICZkZXYtPmNt
ZDsKPiArCWNsZWFyX29wYWxfY21kKGNtZCk7Cj4gKwo+ICsJc2V0X2NvbUlEKGNtZCwgZGV2LT5j
b21JRCk7Cj4gKwo+ICsJc211aWQgPSBPUEFMVUlEW09QQUxfQURNSU5TUF9VSURdOwo+ICsJbWV0
aG9kID0gT1BBTE1FVEhPRFtPUEFMX1JFVkVSVF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgImMycyAyYyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJICAg
IHNtdWlkLCBPUEFMX1VJRF9MRU5HVEgsCj4gKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9M
RU5HVEgsCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNU
KTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgUkVW
RVJUIFRQRVIgY29tbWFuZC5cbiIsCj4gKwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsKPiArCQly
ZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiArCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNt
ZCwgZ2VuZXJpY19jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBpbnRlcm5hbF9hY3RpdmF0
ZV91c2VyKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwljb25zdCB1OCAqbWV0aG9kOwo+
ICsJdTggdWlkW09QQUxfVUlEX0xFTkdUSF07Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKPiAr
CWludCByZXQ7Cj4gKwlzdHJ1Y3Qgb3BhbF9hY3RpdmF0ZV91c2VyICphY3Q7Cj4gKwo+ICsJY21k
ID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCXNldF9jb21JRChjbWQs
IGRldi0+Y29tSUQpOwo+ICsKPiArCWFjdCA9IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAx
XTsKPiArCj4gKwltZW1jcHkodWlkLCBPUEFMVUlEW09QQUxfVVNFUjFfVUlEXSwgT1BBTF9VSURf
TEVOR1RIKTsKPiArCXVpZFs3XSA9IGFjdC0+d2hvLndobzsKPiArCj4gKwltZXRob2QgPSBPUEFM
TUVUSE9EW09QQUxfU0VUXTsKPiArCj4gKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21k
LCAiYzJzIDNjIGMgNGMgM2MiLAo+ICsJCQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAgICB1aWQs
IE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwK
PiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUs
Cj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDEsIC8qIFZhbHVlcyAqLwo+ICsKPiArCQkJCSAg
ICBPUEFMX1NUQVJUTElTVCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkg
ICAgT1BBTF9USU5ZX1VJTlRfMDUsIC8qIEVuYWJsZWQgKi8KPiArCQkJCSAgICBPUEFMX1RJTllf
VUlOVF8wMSwgLyogVHJ1ZSAqLwo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCj4gKwkJCQkg
ICAgT1BBTF9FTkRMSVNULAo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCQkJCSAgICBPUEFM
X0VORExJU1QpOwo+ICsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3Ig
YnVpbGRpbmcgQWN0aXZhdGUgVXNlck4gY29tbWFuZC5cbiIsCj4gKwkJICAgICAgIGRldi0+ZGlz
a19uYW1lKTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiArCXJldHVybiBmaW5hbGl6ZV9h
bmRfc2VuZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBl
cmFzZV9sb2NraW5nX3JhbmdlKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwljb25zdCB1
OCAqbWV0aG9kOwo+ICsJdTggdWlkW09QQUxfVUlEX0xFTkdUSF07Cj4gKwlzdHJ1Y3Qgb3BhbF9j
bWQgKmNtZDsKPiArCWludCByZXQ7Cj4gKwo+ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJf
b3BhbF9jbWQoY21kKTsKPiArCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOwo+ICsKPiArCW1l
dGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9FUkFTRV07Cj4gKwo+ICsJaWYgKGJ1aWxkX2xvY2tpbmdf
cmFuZ2UodWlkLCBzaXplb2YodWlkKSwgZGV2LT5scikgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczog
Q2FuJ3QgYnVpbGQgbG9ja2luZyByYW5nZVxuIiwgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVy
biAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQs
ICJjMnMgMmMiLAo+ICsJCQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAgICB1aWQsIE9QQUxfVUlE
X0xFTkdUSCwKPiArCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJ
CQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCj4gKwlp
ZiAocmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIEVyYXNlIExvY2tp
bmcgUmFuZ2UgQ21tYW5kLlxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJl
dHVybiByZXQ7Cj4gKwl9Cj4gKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdl
bmVyaWNfY29udCk7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgc2V0X21icl9kb25lKHN0cnVjdCBv
cGFsX2RldiAqZGV2KQo+ICt7Cj4gKwljb25zdCB1OCAqbWV0aG9kLCAqdWlkOwo+ICsJc3RydWN0
IG9wYWxfY21kICpjbWQ7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCXU4IG1icl9kb25lX3RmID0gKih1
OCAqKWRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKPiArCj4gKwljbWQgPSAmZGV2LT5j
bWQ7Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+ICsJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21J
RCk7Cj4gKwo+ICsJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX1NFVF07Cj4gKwl1aWQgPSBPUEFM
VUlEW09QQUxfTUJSQ09OVFJPTF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3Zh
KGNtZCwgImMycyAzYyA2YyAyYyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJICAgIHVp
ZCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RI
LAo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICBPUEFMX1NUQVJUTkFN
RSwKPiArCQkJCSAgICBPUEFMX1ZBTFVFUywKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1Qs
Cj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDIs
IC8qIERvbmUgKi8KPiArCQkJCSAgICBtYnJfZG9uZV90ZiwgICAgICAgLyogRG9uZSBUIG9yIEYg
Ki8KPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNULAo+ICsK
PiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCWlm
IChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgQnVpbGRpbmcgc2V0IE1CUiBEb250
L05vdCBkb25lIGNvbW1hbmRcbiIsCnMvRG9udC9Eb25lLyA/CgoKPiArCQkgICAgICAgZGV2LT5k
aXNrX25hbWUpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIGZpbmFsaXpl
X2FuZF9zZW5kKGRldiwgY21kLCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50
IHNldF9tYnJfZW5hYmxlX2Rpc2FibGUoc3RydWN0IG9wYWxfZGV2ICpkZXYpCj4gK3sKPiArCWNv
bnN0IHU4ICptZXRob2QsICp1aWQ7Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKPiArCWludCBy
ZXQ7Cj4gKwo+ICsJdTggbWJyX2VuX2RpcyA9ICoodTggKilkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0
YXRlIC0gMV07Cj4gKwo+ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21k
KTsKPiArCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOwo+ICsKPiArCW1ldGhvZCA9IE9QQUxN
RVRIT0RbT1BBTF9TRVRdOwo+ICsJdWlkID0gT1BBTFVJRFtPUEFMX01CUkNPTlRST0xdOwo+ICsK
PiArCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMgM2MgNmMgMmMiLAo+ICsJ
CQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJ
CSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFS
VExJU1QsCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9WQUxVRVMs
Cj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNULAo+ICsJCQkJICAgIE9QQUxfU1RBUlROQU1F
LAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAxLCAvKiBFbmFibGUgKi8KPiArCQkJCSAgICBt
YnJfZW5fZGlzLCAgICAgICAgLyogRW5hYmxlIG9yIERpc2FibGUgKi8KPiArCQkJCSAgICBPUEFM
X0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNULAo+ICsKPiArCQkJCSAgICBPUEFMX0VO
RE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJ
cHJfZXJyKCIlczogRXJyb3IgQnVpbGRpbmcgc2V0IE1CUiBEb250L05vdCBkb25lIGNvbW1hbmRc
biIsCnMvRG9udC9Eb25lLyA/CgoKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJl
dHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21k
LCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNldF9uZXdfcHcoc3RydWN0
IG9wYWxfZGV2ICpkZXYpCj4gK3sKPiArCWNvbnN0IHU4ICptZXRob2Q7Cj4gKwl1OCBjcGluX3Vp
ZFtPUEFMX1VJRF9MRU5HVEhdOwo+ICsJc3RydWN0IG9wYWxfY21kICpjbWQ7Cj4gKwlpbnQgcmV0
Owo+ICsJc3RydWN0IG9wYWxfbmV3X3B3ICpwdzsKPiArCXNpemVfdCBrZXlfbGVuOwo+ICsJdTgg
KmtleTsKPiArCj4gKwljbWQgPSAmZGV2LT5jbWQ7Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+
ICsJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7Cj4gKwo+ICsJcHcgPSBkZXYtPmZ1bmNfZGF0
YVtkZXYtPnN0YXRlIC0gMV07Cj4gKwlrZXkgPSBwdy0+bmV3X3Bpbi5rZXk7Cj4gKwlrZXlfbGVu
ID0gcHctPm5ld19waW4ua2V5X2xlbjsKPiArCW1lbWNweShjcGluX3VpZCwgT1BBTFVJRFtPUEFM
X0NfUElOX0FETUlOMV0sIE9QQUxfVUlEX0xFTkdUSCk7Cj4gKwo+ICsJaWYgKHB3LT51c2VyX2Zv
cl9wdyAhPSBPUEFMX0FETUlOMSkgewo+ICsJCWNwaW5fdWlkWzVdID0gMHgwMzsKPiArCQlpZiAo
cHctPndoby5TVU0pCj4gKwkJCWNwaW5fdWlkWzddID0gcHctPm5ld19waW4ubHIgKyAxOwo+ICsJ
CWVsc2UKPiArCQkJY3Bpbl91aWRbN10gPSBwdy0+dXNlcl9mb3JfcHc7Cj4gKwl9Cj4gKwo+ICsJ
bWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX1NFVF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgImMycyAzYyAzY3MyYyAyYyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+
ICsJCQkJICAgIGNwaW5fdWlkLCBPUEFMX1VJRF9MRU5HVEgsCj4gKwkJCQkgICAgbWV0aG9kLCBP
UEFMX01FVEhPRF9MRU5HVEgsCj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNULAo+ICsJCQkJ
ICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAxLCAvKiBWYWx1
ZXMgKi8KPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9TVEFS
VE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIFBJTiAqLwo+ICsJCQkJICAg
IGtleSwga2V5X2xlbiwKPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9F
TkRMSVNULAo+ICsKPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRM
SVNUKTsKPiArCj4gKwlpZiAocmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxk
aW5nIFNFVCBBTUlOMSBQSU4gY29tbWFuZC5cbiIsCj4gKwkJICAgICAgIGRldi0+ZGlza19uYW1l
KTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiArCXJldHVybiBmaW5hbGl6ZV9hbmRfc2Vu
ZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBzZXRfc2lk
X2NwaW5fcGluKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwljb25zdCB1OCAqbWV0aG9k
LCAqY3Bpbl91aWQ7Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKPiArCWludCByZXQ7Cj4gKwo+
ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCXNldF9jb21J
RChjbWQsIGRldi0+Y29tSUQpOwo+ICsKPiArCWNwaW5fdWlkID0gT1BBTFVJRFtPUEFMX0NfUElO
X1NJRF07Cj4gKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfU0VUXTsKPiArCj4gKwlyZXQgPSB0
ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDJjIDRjczJjIDJjIiwKPiArCQkJCSAgICBP
UEFMX0NBTEwsCj4gKwkJCQkgICAgY3Bpbl91aWQsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJCSAg
ICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJ
U1QsCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwo+ICsJCQkJICAgIE9QQUxfVElOWV9V
SU5UXzAxLCAvKiBWYWx1ZXMgKi8KPiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAg
ICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMywgLyogUElOICov
Cj4gKwkJCQkgICAgZGV2LT5rZXksIGRldi0+a2V5X2xlbiwKPiArCQkJCSAgICBPUEFMX0VORE5B
TUUsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNULAo+ICsKPiArCQkJCSAgICBPUEFMX0VORE5BTUUs
Cj4gKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCj4gKwlpZiAocmV0IDwgMCkgewo+ICsJCXBy
X2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIFNFVCBDUElOIFBJTiBjb21tYW5kLlxuIiwKPiArCQkg
ICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJcmV0
dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+
ICtzdGF0aWMgdm9pZCBxdWVyeV9sb2NraW5nX3JhbmdlX2NvbnQoaW50IGVycm9yLCB2b2lkICpk
YXRhKQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7Cj4gKwo+ICsJaWYgKGVy
cm9yKQo+ICsJCWdvdG8gZXJyX3JldHVybjsKPiArCj4gKwllcnJvciA9IHBhcnNlX2FuZF9jaGVj
a19zdGF0dXMoZGV2KTsKPiArCWlmIChlcnJvcikKPiArCQlnb3RvIGVycl9yZXR1cm47Cj4gKwo+
ICsJZGV2LT5zdGFydCA9IHJlc3BvbnNlX2dldF91NjQoJmRldi0+cGFyc2VkLCA0KTsKPiArCWRl
di0+bGVuZ3RoID0gcmVzcG9uc2VfZ2V0X3U2NCgmZGV2LT5wYXJzZWQsIDgpOwo+ICsKPiArZXJy
X3JldHVybjoKPiArCWlmIChkZXYtPm9wZXJfY2IpCj4gKwkJZGV2LT5vcGVyX2NiKGVycm9yLCBk
ZXYpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHF1ZXJ5X2xvY2tpbmdfcmFuZ2Uoc3RydWN0IG9w
YWxfZGV2ICpkZXYpCj4gK3sKPiArCXU4IGxyX2J1ZmZlcltPUEFMX1VJRF9MRU5HVEhdOwo+ICsJ
c3RydWN0IG9wYWxfY21kICpjbWQ7Cj4gKwljb25zdCB1OCAqbWV0aG9kOwo+ICsJaW50IHJldDsK
PiArCj4gKwljbWQgPSAmZGV2LT5jbWQ7Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+ICsKPiAr
CW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9HRVRdOwo+ICsKPiArCWlmIChidWlsZF9sb2NraW5n
X3JhbmdlKGxyX2J1ZmZlciwgc2l6ZW9mKGxyX2J1ZmZlciksIGRldi0+bHIpIDwgMCkgewo+ICsJ
CXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgcmFuZ2VcbiIsIGRldi0+ZGlza19uYW1l
KTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0KPiArCj4gKwlzZXRfY29tSUQoY21kLCBkZXYt
PmNvbUlEKTsKPiArCj4gKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDEy
YyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJICAgIGxyX2J1ZmZlciwgT1BBTF9VSURf
TEVOR1RILAo+ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAo+ICsKPiArCQkJ
CSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAg
ICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1NUQVJUQ09MVU1OLAo+ICsJCQkJICAg
IE9QQUxfUkFOR0VTVEFSVCwKPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BB
TF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRDT0xVTU4sCj4gKwkJCQkgICAgT1BBTF9S
QU5HRUxFTkdUSCwKPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRM
SVNULAo+ICsJCQkJICAgIE9QQUxfRU5ETElTVCk7Cj4gKwo+ICsJaWYgKHJldCA8IDApIHsKPiAr
CQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBHRVQgTG9ja2luZyBSYW5nZSBjb21tYW5kLlxu
IiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9Cj4g
Kwo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBxdWVyeV9sb2NraW5nX3Jh
bmdlX2NvbnQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGFkZF91c2VyX3RvX2xyKHN0cnVjdCBv
cGFsX2RldiAqZGV2KQo+ICt7Cj4gKwl1OCBscl9idWZmZXJbT1BBTF9VSURfTEVOR1RIXTsKPiAr
CXU4IHVzZXJfdWlkW09QQUxfVUlEX0xFTkdUSF07Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsK
PiArCWNvbnN0IHU4ICptZXRob2Q7Cj4gKwlzdHJ1Y3Qgb3BhbF9sb2NrX3VubG9jayAqbGt1bDsK
PiArCWludCByZXQ7Cj4gKwo+ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQo
Y21kKTsKPiArCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOwo+ICsKPiArCW1ldGhvZCA9IE9Q
QUxNRVRIT0RbT1BBTF9TRVRdOwo+ICsKPiArCWxrdWwgPSBkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0
YXRlIC0gMV07Cj4gKwo+ICsJbWVtY3B5KGxyX2J1ZmZlciwgT1BBTFVJRFtPUEFMX0xPQ0tJTkdS
QU5HRV9BQ0VfUkRMT0NLRURdLAo+ICsJICAgICAgIE9QQUxfVUlEX0xFTkdUSCk7Cj4gKwo+ICsJ
aWYgKGxrdWwtPmxfc3RhdGUgPT0gT1BBTF9SVykKPiArCQltZW1jcHkobHJfYnVmZmVyLCBPUEFM
VUlEW09QQUxfTE9DS0lOR1JBTkdFX0FDRV9XUkxPQ0tFRF0sCj4gKwkJICAgICAgIE9QQUxfVUlE
X0xFTkdUSCk7Cj4gKwo+ICsJbHJfYnVmZmVyWzddID0gZGV2LT5scjsKPiArCj4gKwltZW1jcHko
dXNlcl91aWQsIE9QQUxVSURbT1BBTF9VU0VSMV9VSURdLCBPUEFMX1VJRF9MRU5HVEgpOwo+ICsJ
dXNlcl91aWRbN10gPSBsa3VsLT5hdXRob3JpdHkud2hvOwo+ICsKPiArCXJldCA9IHRlc3RfYW5k
X2FkZF90b2tlbl92YShjbWQsICJjMnMgM2MgM2MgMmMgMnNjIGMyc2MgY3MyYyA1YyIsCj4gKwkJ
CQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJICAgIGxyX2J1ZmZlciwgT1BBTF9VSURfTEVOR1RILAo+
ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAo+ICsKPiArCQkJCSAgICBPUEFM
X1NUQVJUTElTVCwKPiArCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1RJ
TllfVUlOVF8wMSwgLyogVmFsdWVzICovCj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNULAo+
ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAzLCAv
KiBCb29sZWFuRXhwciAqLwo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAg
ICBPUEFMX1NUQVJUTkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTFVJRFtPUEFMX0hBTEZfVUlEX0FV
VEhPUklUWV9PQkpfUkVGXSwKPiArCQkJCSAgICBPUEFMX1VJRF9MRU5HVEhfSEFMRiwKPiArCQkJ
CSAgICB1c2VyX3VpZCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwK
PiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTFVJRFtPUEFMX0hB
TEZfVUlEX0FVVEhPUklUWV9PQkpfUkVGXSwKPiArCQkJCSAgICBPUEFMX1VJRF9MRU5HVEhfSEFM
RiwKPiArCQkJCSAgICB1c2VyX3VpZCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIE9QQUxf
RU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTFVJ
RFtPUEFMX0hBTEZfVUlEX0JPT0xFQU5fQUNFXSwKPiArCQkJCSAgICBPUEFMX1VJRF9MRU5HVEhf
SEFMRiwKPiArCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMSwKPiArCQkJCSAgICBPUEFMX0VORE5B
TUUsCj4gKwo+ICsJCQkJICAgIE9QQUxfRU5ETElTVCwKPiArCQkJCSAgICBPUEFMX0VORE5BTUUs
Cj4gKwkJCQkgICAgT1BBTF9FTkRMSVNULAo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCQkJ
CSAgICBPUEFMX0VORExJU1QpOwo+ICsJaWYgKHJldCA8IDApIHsKPiArCQlwcl9lcnIoIiVzOiBF
cnJvciBidWlsZGluZyBhZGQgdXNlciB0byBsb2NraW5nIHJhbmdlIGNvbW1hbmQuXG4iLAo+ICsJ
CSAgICAgICBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJcmV0dXJuIHJldDsKPiArCX0KPiArCj4gKwly
ZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdlbmVyaWNfY29udCk7Cj4gK30KPiAr
Cj4gK3N0YXRpYyBpbnQgbG9ja191bmxvY2tfbG9ja2luZ19yYW5nZShzdHJ1Y3Qgb3BhbF9kZXYg
KmRldikKPiArewo+ICsJdTggbHJfYnVmZmVyW09QQUxfVUlEX0xFTkdUSF07Cj4gKwlzdHJ1Y3Qg
b3BhbF9jbWQgKmNtZDsKPiArCWNvbnN0IHU4ICptZXRob2Q7Cj4gKwlzdHJ1Y3Qgb3BhbF9sb2Nr
X3VubG9jayAqbGt1bDsKPiArCWludCByZXQ7Cj4gKwl1OCByZWFkX2xvY2tlZCA9IDEsIHdyaXRl
X2xvY2tlZCA9IDE7Cj4gKwo+ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQo
Y21kKTsKPiArCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOwo+ICsKPiArCW1ldGhvZCA9IE9Q
QUxNRVRIT0RbT1BBTF9TRVRdOwo+ICsJbGt1bCA9IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUg
LSAxXTsKPiArCWlmIChidWlsZF9sb2NraW5nX3JhbmdlKGxyX2J1ZmZlciwgc2l6ZW9mKGxyX2J1
ZmZlciksIGRldi0+bHIpIDwgMCkgewo+ICsJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tp
bmcgcmFuZ2VcbiIsIGRldi0+ZGlza19uYW1lKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0K
PiArCj4gKwlzd2l0Y2ggKGxrdWwtPmxfc3RhdGUpIHsKPiArCWNhc2UgT1BBTF9STzoKPiArCQly
ZWFkX2xvY2tlZCA9IDA7Cj4gKwkJd3JpdGVfbG9ja2VkID0gMTsKPiArCQlicmVhazsKPiArCWNh
c2UgT1BBTF9SVzoKPiArCQlyZWFkX2xvY2tlZCA9IDA7Cj4gKwkJd3JpdGVfbG9ja2VkID0gMDsK
PiArCQlicmVhazsKPiArCWNhc2UgT1BBTF9MSzoKPiArCQkvKiB2YXJzIGFyZSBpbml0YWxpemVk
IHRvIGxvY2tlZCAqLwo+ICsJCWJyZWFrOwo+ICsJZGVmYXVsdDoKPiArCQlwcl9lcnIoIlRyaWVk
IHRvIHNldCBhbiBpbnZhbGlkIGxvY2tpbmcgc3RhdGUuLi4gcmV0dXJuaW5nIHRvIHVsYW5kXG4i
KTsKPiArCQlyZXR1cm4gMTsKPiArCX0KPiArCj4gKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5f
dmEoY21kLCAiYzJzYyAzYyA0YyA0YyAzYyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJ
ICAgIGxyX2J1ZmZlciwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9N
RVRIT0RfTEVOR1RILAo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNULAo+ICsKPiArCQkJCSAgICBP
UEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1ZBTFVFUywKPiArCQkJCSAgICBPUEFMX1NU
QVJUTElTVCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9S
RUFETE9DS0VELAo+ICsJCQkJICAgIHJlYWRfbG9ja2VkLAo+ICsJCQkJICAgIE9QQUxfRU5ETkFN
RSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9XUklURUxP
Q0tFRCwKPiArCQkJCSAgICB3cml0ZV9sb2NrZWQsCj4gKwkJCQkgICAgT1BBTF9FTkROQU1FLAo+
ICsKPiArCQkJCSAgICBPUEFMX0VORExJU1QsCj4gKwkJCQkgICAgT1BBTF9FTkROQU1FLAo+ICsJ
CQkJICAgIE9QQUxfRU5ETElTVCk7Cj4gKwo+ICsJaWYgKHJldCA8IDApIHsKPiArCQlwcl9lcnIo
IiVzOiBFcnJvciBidWlsZGluZyBTRVQgY29tbWFuZC5cbiIsIGRldi0+ZGlza19uYW1lKTsKPiAr
CQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21k
LCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+ICsKPiArc3RhdGljIGludCBsb2NrX3VubG9ja19s
b2NraW5nX3JhbmdlX1NVTShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJdTggbHJfYnVm
ZmVyW09QQUxfVUlEX0xFTkdUSF07Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKPiArCWNvbnN0
IHU4ICptZXRob2Q7Cj4gKwlzdHJ1Y3Qgb3BhbF9sb2NrX3VubG9jayAqbGt1bDsKPiArCWludCBy
ZXQ7Cj4gKwl1OCByZWFkX2xvY2tlZCA9IDEsIHdyaXRlX2xvY2tlZCA9IDE7Cj4gKwo+ICsJY21k
ID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCXNldF9jb21JRChjbWQs
IGRldi0+Y29tSUQpOwo+ICsKPiArCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9TRVRdOwo+ICsJ
bGt1bCA9IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKPiArCWlmIChidWlsZF9sb2Nr
aW5nX3JhbmdlKGxyX2J1ZmZlciwgc2l6ZW9mKGxyX2J1ZmZlciksIGRldi0+bHIpIDwgMCkgewo+
ICsJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgcmFuZ2VcbiIsIGRldi0+ZGlza19u
YW1lKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0KPiArCj4gKwlzd2l0Y2ggKGxrdWwtPmxf
c3RhdGUpIHsKPiArCWNhc2UgT1BBTF9STzoKPiArCQlyZWFkX2xvY2tlZCA9IDA7Cj4gKwkJd3Jp
dGVfbG9ja2VkID0gMTsKPiArCQlicmVhazsKPiArCWNhc2UgT1BBTF9SVzoKPiArCQlyZWFkX2xv
Y2tlZCA9IDA7Cj4gKwkJd3JpdGVfbG9ja2VkID0gMDsKPiArCQlicmVhazsKPiArCWNhc2UgT1BB
TF9MSzoKPiArCQkvKiB2YXJzIGFyZSBpbml0YWxpemVkIHRvIGxvY2tlZCAqLwo+ICsJCWJyZWFr
Owo+ICsJZGVmYXVsdDoKPiArCQlwcl9lcnIoIlRyaWVkIHRvIHNldCBhbiBpbnZhbGlkIGxvY2tp
bmcgc3RhdGUuXG4iKTsKPiArCQlyZXR1cm4gMTsKPiArCX0KPiArCj4gKwlyZXQgPSB0ZXN0X2Fu
ZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzYyAzYyA0YyA0YyA0YyA0YyAzYyIsCj4gKwkJCQkgICAg
T1BBTF9DQUxMLAo+ICsJCQkJICAgIGxyX2J1ZmZlciwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJ
ICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNU
LAo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1ZBTFVFUywK
PiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUs
Cj4gKwkJCQkgICAgT1BBTF9SRUFETE9DS0VOQUJMRUQsCj4gKwkJCQkgICAgT1BBTF9UUlVFLAo+
ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4g
KwkJCQkgICAgT1BBTF9XUklURUxPQ0tFTkFCTEVELAo+ICsJCQkJICAgIE9QQUxfVFJVRSwKPiAr
CQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJ
CQkJICAgIE9QQUxfUkVBRExPQ0tFRCwKPiArCQkJCSAgICByZWFkX2xvY2tlZCwKPiArCQkJCSAg
ICBPUEFMX0VORE5BTUUsCj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAg
IE9QQUxfV1JJVEVMT0NLRUQsCj4gKwkJCQkgICAgd3JpdGVfbG9ja2VkLAo+ICsJCQkJICAgIE9Q
QUxfRU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNULAo+ICsJCQkJICAgIE9QQUxf
RU5ETkFNRSwKPiArCQkJCSAgICBPUEFMX0VORExJU1QpOwo+ICsJaWYgKHJldCA8IDApIHsKPiAr
CQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBTRVQgY29tbWFuZC5cbiIsIGRldi0+ZGlza19u
YW1lKTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5k
KGRldiwgY21kLCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+ICtpbnQgYWN0aXZhdGVfbHNwKHN0
cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwl1OCB1c2VyX2xyW09QQUxfVUlEX0xFTkdUSF07
Cj4gKwljb25zdCB1OCAqbWV0aG9kLCAqdWlkOwo+ICsJc3RydWN0IG9wYWxfY21kICpjbWQ7Cj4g
KwlpbnQgcmV0Owo+ICsJc2l6ZV90IHVpbnRfMyA9IDB4ODM7Cj4gKwo+ICsJY21kID0gJmRldi0+
Y21kOwo+ICsKPiArCWNsZWFyX29wYWxfY21kKGNtZCk7Cj4gKwlzZXRfY29tSUQoY21kLCBkZXYt
PmNvbUlEKTsKPiArCj4gKwl1aWQgPSBPUEFMVUlEW09QQUxfTE9DS0lOR1NQX1VJRF07Cj4gKwlt
ZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfQUNUSVZBVEVdOwo+ICsKPiArCXJldCA9IHRlc3RfYW5k
X2FkZF90b2tlbl92YShjbWQsICJjMnMiLAo+ICsJCQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAg
ICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xF
TkdUSCk7Cj4gKwlpZiAocmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5n
IEFjdGl2YXRlIExvY2tpbmdTUCBjb21tYW5kLlxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25h
bWUpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9Cj4gKwkvKiBBY3RpdmF0aW5nIGFzIFNVTSAqLwo+
ICsJaWYgKGRldi0+bHIgPiAwKSB7Cj4gKwkJcmV0ID0gYnVpbGRfbG9ja2luZ19yYW5nZSh1c2Vy
X2xyLCBzaXplb2YodXNlcl9sciksIGRldi0+bHIpOwo+ICsJCWlmIChyZXQgPCAwKSB7Cj4gKwkJ
CXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgdXNlclxuIiwKPiArCQkJICAgICAgIGRl
di0+ZGlza19uYW1lKTsKPiArCQkJcmV0dXJuIHJldDsKPiArCQl9Cj4gKwkJdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgIjJjIDRjIGNzYyAyYyIsCj4gKwkJCQkgICAgICBPUEFMX1NUQVJUTElT
VCwKPiArCQkJCSAgICAgIE9QQUxfU1RBUlROQU1FLAo+ICsKPiArCQkJCSAgICAgIHVpbnRfMywK
PiArCQkJCSAgICAgIE9QQUxfVElOWV9VSU5UXzA2LAo+ICsJCQkJICAgICAgT1BBTF9USU5ZX1VJ
TlRfMDAsCj4gKwkJCQkgICAgICBPUEFMX1RJTllfVUlOVF8wMCwKPiArCj4gKwkJCQkgICAgICBP
UEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICAgIHVzZXJfbHIsIE9QQUxfVUlEX0xFTkdUSCwKPiAr
CQkJCSAgICAgIE9QQUxfRU5ETElTVCwKPiArCj4gKwkJCQkgICAgICBPUEFMX0VORE5BTUUsCj4g
KwkJCQkgICAgICBPUEFMX0VORExJU1QpOwo+ICsJfSBlbHNlIC8qIEFjdGlhdmUgTm9ybWFsIE1v
ZGUgKi8KPiArCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiMmMiLAo+ICsJCQkJ
CSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCj4gKwlp
ZiAocmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIEFjdGl2YXRlIExv
Y2tpbmdTUCBjb21tYW5kLlxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJl
dHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21k
LCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBnZXRfbHNwX2xpZmVjeWNs
ZV9jb250KGludCBlcnJvciwgdm9pZCAqZGF0YSkKPiArewo+ICsKPiArCXN0cnVjdCBvcGFsX2Rl
diAqZGV2ID0gZGF0YTsKPiArCXU4IGxjX3N0YXR1czsKPiArCj4gKwlpZiAoZXJyb3IpCj4gKwkJ
Z290byBlcnJfcmV0dXJuOwo+ICsKPiArCWVycm9yID0gcGFyc2VfYW5kX2NoZWNrX3N0YXR1cyhk
ZXYpOwo+ICsJaWYgKGVycm9yKQo+ICsJCWdvdG8gZXJyX3JldHVybjsKPiArCj4gKwlsY19zdGF0
dXMgPSByZXNwb25zZV9nZXRfdTY0KCZkZXYtPnBhcnNlZCwgNCk7Cj4gKwkvKiAweDA4IGlzIE1h
bnVmYWN1cmVkIEluYWN0aXZlICovCj4gKwkvKiAweDA5IGlzIE1hbnVmYWN0dXJlZCAqLwo+ICsJ
aWYgKGxjX3N0YXR1cyAhPSAweDA4KSB7Cj4gKwkJcHJfZXJyKCIlczogQ291bGRuJ3QgZGV0ZXJt
aW5lIHRoZSBzdGF0dXMgb2YgdGhlIExpZmN5Y2xlIHN0YXRlXG4iLAo+ICsJCSAgICAgICBkZXYt
PmRpc2tfbmFtZSk7Cj4gKwkJZXJyb3IgPSAtRU5PREVWOwo+ICsJfQo+ICsKPiArZXJyX3JldHVy
bjoKPiArCWlmIChkZXYtPm9wZXJfY2IpCj4gKwkJZGV2LT5vcGVyX2NiKGVycm9yLCBkZXYpOwo+
ICt9Cj4gKwo+ICsvKiBEZXRlcm1pbmUgaWYgd2UncmUgaW4gdGhlIE1hbnVmYWN0dXJlZCBJbmFj
dGl2ZSBvciBBY3RpdmUgc3RhdGUgKi8KPiAraW50IGdldF9sc3BfbGlmZWN5Y2xlKHN0cnVjdCBv
cGFsX2RldiAqZGV2KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKPiArCWNvbnN0IHU4
ICptZXRob2QsICp1aWQ7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWNtZCA9ICZkZXYtPmNtZDsKPiAr
Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+ICsJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7
Cj4gKwo+ICsJdWlkID0gT1BBTFVJRFtPUEFMX0xPQ0tJTkdTUF9VSURdOwo+ICsJbWV0aG9kID0g
T1BBTE1FVEhPRFtPUEFMX0dFVF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3Zh
KGNtZCwgImMycyAyYyA0YyA0YyAyYyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJICAg
IHVpZCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVO
R1RILAo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICBPUEFMX1NUQVJU
TElTVCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5Z
X1VJTlRfMDMsIC8qIFN0YXJ0IENvbHVtbiAqLwo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzA2
LCAvKiBMaWZjeWNsZSBDb2x1bW4gKi8KPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwo+ICsJ
CQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzA0LCAvKiBF
bmQgQ29sdW1uICovCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDYsIC8qIExpZmVjeWNsZSBD
b2x1bW4gKi8KPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwo+ICsJCQkJICAgIE9QQUxfRU5E
TElTVCwKPiArCQkJCSAgICBPUEFMX0VORExJU1QpOwo+ICsKPiArCWlmIChyZXQgPCAwKSB7Cj4g
KwkJcHJfZXJyKCIlczogRXJyb3IgQnVpbGRpbmcgR0VUIExpZmVjeWNsZSBTdGF0dXMgY29tbWFu
ZFxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9
Cj4gKwo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZXRfbHNwX2xpZmVj
eWNsZV9jb250KTsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgZ2V0X21zaWRfY3Bpbl9waW5fY29u
dChpbnQgZXJyb3IsIHZvaWQgKmRhdGEpCj4gK3sKPiArCWNvbnN0IGNoYXIgKm1zaWRfcGluOwo+
ICsJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOwo+ICsJc2l6ZV90IHN0cmxlbjsKPiArCj4g
KwlpZiAoZXJyb3IpCj4gKwkJZ290byBlcnJfcmV0dXJuOwo+ICsKPiArCWVycm9yID0gcGFyc2Vf
YW5kX2NoZWNrX3N0YXR1cyhkZXYpOwo+ICsJaWYgKGVycm9yKQo+ICsJCWdvdG8gZXJyX3JldHVy
bjsKPiArCj4gKwlzdHJsZW4gPSByZXNwb25zZV9nZXRfc3RyaW5nKCZkZXYtPnBhcnNlZCwgNCwg
Jm1zaWRfcGluKTsKPiArCWlmICghbXNpZF9waW4pIHsKPiArCQlwcl9lcnIoIiVzOiBDb3VsZG4n
dCBleHRyYWN0IFBJTiBmcm9tIHJlc3BvbnNlXG4iLCBfX2Z1bmNfXyk7Cj4gKwkJZXJyb3IgPSAx
Owo+ICsJCWdvdG8gZXJyX3JldHVybjsKPiArCX0KPiArCj4gKwlkZXYtPnByZXZfZGF0YSA9IGtt
ZW1kdXAobXNpZF9waW4sIHN0cmxlbiwgR0ZQX0tFUk5FTCk7Cj4gKwlpZiAoIWRldi0+cHJldl9k
YXRhKQo+ICsJCWVycm9yID0gLUVOT01FTTsKPiArCj4gKwlkZXYtPnByZXZfZF9sZW4gPSBzdHJs
ZW47Cj4gKwo+ICsgZXJyX3JldHVybjoKPiArCWlmIChkZXYtPm9wZXJfY2IpCj4gKwkJZGV2LT5v
cGVyX2NiKGVycm9yLCBkZXYpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGdldF9tc2lkX2NwaW5f
cGluKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwljb25zdCB1OCAqbWV0aG9kLCAqc211
aWQ7Cj4gKwlpbnQgcmV0Owo+ICsJc3RydWN0IG9wYWxfY21kICpjbWQ7Cj4gKwo+ICsJY21kID0g
JmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCXNldF9jb21JRChjbWQsIGRl
di0+Y29tSUQpOwo+ICsKPiArCXNtdWlkID0gT1BBTFVJRFtPUEFMX0NfUElOX01TSURdOwo+ICsJ
bWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX0dFVF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgImMgMnMgMTJjIiwKPiArCQkJCSAgICBPUEFMX0NBTEwsCj4gKwo+ICsJ
CQkJICAgIHNtdWlkLCBPUEFMX1VJRF9MRU5HVEgsCj4gKwkJCQkgICAgbWV0aG9kLCBPUEFMX01F
VEhPRF9MRU5HVEgsCj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNULAo+ICsJCQkJICAgIE9Q
QUxfU1RBUlRMSVNULAo+ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxf
VElOWV9VSU5UXzAzLCAvKiBTYXJ0IENvbHVtbiAqLwo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5U
XzAzLCAvKiBQSU4gKi8KPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9T
VEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDQsIC8qIEVuZCBDb2x1bW4gKi8K
PiArCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMywgLyogUElOICovCj4gKwkJCQkgICAgT1BBTF9F
TkROQU1FLAo+ICsJCQkJICAgIE9QQUxfRU5ETElTVCwKPiArCQkJCSAgICBPUEFMX0VORExJU1Qp
Owo+ICsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcg
R2V0IE1TSUQgQ1BJTiBQSU4gY29tbWFuZC5cbiIsCj4gKwkJICAgICAgIGRldi0+ZGlza19uYW1l
KTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiArCXJldHVybiBmaW5hbGl6ZV9hbmRfc2Vu
ZChkZXYsIGNtZCwgZ2V0X21zaWRfY3Bpbl9waW5fY29udCk7Cj4gK30KPiArCj4gK3N0YXRpYyB2
b2lkIHVubG9ja19zdXNwZW5kX2ZpbmFsKGludCBlcnJvciwgdm9pZCAqZGF0YSkKPiArewo+ICsJ
c3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOwo+ICsKPiArCWRldi0+cmVzdW1lX2Zyb21fc3Vz
cGVuZCA9IGZhbHNlOwo+ICsJZGV2LT5yZXN1bWVfZGF0YSA9IE5VTEw7Cj4gKwlkZXYtPmZ1bmNf
ZGF0YSA9IE5VTEw7Cj4gKwlkZXYtPmJkZXYgPSBOVUxMOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50
IGJ1aWxkX2VuZF9vcGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2ICpkZXYpCj4gK3sKPiArCXN0
cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsKPiArCWNtZCA9ICZkZXYtPmNtZDsKPiArCWNsZWFyX29w
YWxfY21kKGNtZCk7Cj4gKwo+ICsJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7Cj4gKwlyZXR1
cm4gdGVzdF9hbmRfYWRkX3Rva2VuX3U4KGNtZCwgT1BBTF9FTkRPRlNFU1NJT04pOwo+ICt9Cj4g
Kwo+ICtzdGF0aWMgaW50IGVuZF9vcGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2ICpkZXYpCj4g
K3sKPiArCWlmIChidWlsZF9lbmRfb3BhbF9zZXNzaW9uKGRldikgPCAwKQo+ICsJCXJldHVybiAt
MTsKPiArCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsICZkZXYtPmNtZCwgZW5kX3Nlc3Np
b25fY29udCk7Cj4gK30KQW55IHJlYXNvbiB3ZSBjYW50OgoKaW50IHJldCA9IGJ1aWxkXy4uLgpp
ZiAocmV0IDwgMCkKCXJldHVybiByZXQ7CgoKPiArCj4gK3N0YXRpYyBzdHJ1Y3Qgb3BhbF9kZXYg
KmZpbmRfb3BhbF9kZXYoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgdTggbHIpCj4gK3sKPiAr
CXN0cnVjdCBvcGFsX2RldiAqaXRlciwgKm9wYWxfZGV2ID0gTlVMTDsKPiArCj4gKwlsaXN0X2Zv
cl9lYWNoX2VudHJ5KGl0ZXIsICZvcGFsX2xpc3QsIG5vZGUpIHsKPiArCQlpZiAoc3RybmNtcChp
dGVyLT5kaXNrX25hbWUsIGJkZXYtPmJkX2Rpc2stPmRpc2tfbmFtZSwKPiArCQkJICAgIERJU0tf
TkFNRV9MRU4pKQo+ICsJCQljb250aW51ZTsKPiArCQlpZiAoaXRlci0+bHIgPT0gbHIpIHsKPiAr
CQkJb3BhbF9kZXYgPSBpdGVyOwo+ICsJCQlicmVhazsKPiArCQl9Cj4gKwl9Cj4gKwo+ICsJcmV0
dXJuIG9wYWxfZGV2Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHVwZGF0ZV9vcGFsX2RldihzdHJ1
Y3Qgb3BhbF9kZXYgKm9sZF9kZXYsIHN0cnVjdCBvcGFsX2RldiAqbmV3X2RldikKPiArewo+ICsJ
aWYgKCFhdG9taWNfYWRkX3VubGVzcygmb2xkX2Rldi0+aW5fdXNlLCAxLCAxKSkgewo+ICsJCXBy
X2VycigiJXM6IGRldiB3YXMgaW4gdXNlXG4iLCBfX2Z1bmNfXyk7Cj4gKwkJcmV0dXJuIC1FQlVT
WTsKPiArCX0KPiArCj4gKwlvbGRfZGV2LT5rZXlfbmFtZV9sZW4gPSBuZXdfZGV2LT5rZXlfbmFt
ZV9sZW47Cj4gKwlpZiAoIW1lbWNweShvbGRfZGV2LT5rZXlfbmFtZSwgbmV3X2Rldi0+a2V5X25h
bWUsIG9sZF9kZXYtPmtleV9uYW1lX2xlbikpIHsKPiArCQlwcl9lcnIoIiVzOiBFcnJvciB1cGRh
dGluZyBkZXZpY2U6XG4iLCBvbGRfZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiAtRUZBVUxU
Owo+ICsJfQo+ICsKPiArCWlmICghc3RybmNweShvbGRfZGV2LT5kaXNrX25hbWUsIG5ld19kZXYt
PmRpc2tfbmFtZSwgRElTS19OQU1FX0xFTikpIHsKPiArCQlwcl9lcnIoIiVzOiBFcnJvciByZWdp
c3RlcmluZyBkZXZpY2U6IGNvcHlpbmcgZGlzayBuYW1lXG4iLAo+ICsJCSAgICAgICBvbGRfZGV2
LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiAtRUZBVUxUOwo+ICsJfQo+ICsKPiArCW9sZF9kZXYt
PmNvbUlEID0gbmV3X2Rldi0+Y29tSUQ7Cj4gKwlvbGRfZGV2LT5zdGFydCA9IG5ld19kZXYtPnN0
YXJ0Owo+ICsJb2xkX2Rldi0+bGVuZ3RoID0gbmV3X2Rldi0+bGVuZ3RoOwo+ICsJb2xkX2Rldi0+
YWxpZ24gPSBuZXdfZGV2LT5hbGlnbjsKPiArCW9sZF9kZXYtPmxvd2VzdF9sYmEgPSBuZXdfZGV2
LT5sb3dlc3RfbGJhOwo+ICsJb2xkX2Rldi0+YmRldiA9IE5VTEw7Cj4gKwlvbGRfZGV2LT5maW5h
bF9jYiA9IG5ld19kZXYtPmZpbmFsX2NiOwo+ICsJb2xkX2Rldi0+ZmluYWxfY2JfZGF0YSA9IG5l
d19kZXYtPmZpbmFsX2NiX2RhdGE7Cj4gKwlvbGRfZGV2LT5vcGVyX2NiID0gbmV3X2Rldi0+b3Bl
cl9jYjsKPiArCW9sZF9kZXYtPnN0YXRlID0gbmV3X2Rldi0+c3RhdGU7Cj4gKwlvbGRfZGV2LT5m
dW5jcyA9IG5ld19kZXYtPmZ1bmNzOwo+ICsKPiArCWtmcmVlKG9sZF9kZXYtPmNvbXBsZXRpb24p
Owo+ICsJY2xlYW5fZnVuY3Rpb25fZGF0YShvbGRfZGV2KTsKPiArCj4gKwlvbGRfZGV2LT5jb21w
bGV0aW9uID0gbmV3X2Rldi0+Y29tcGxldGlvbjsKPiArCj4gKwkvKgo+ICsJICogV29uJ3QgYmUg
YWJsZSB0byBhdXRvIHVubG9jayB0aGlzIGxvY2tpbmcgcmFuZ2UgYmFzZWQgb24gYmxvY2sKPiAr
CSAqIHJlcXVlc3Rlcy4KPiArCSAqLwo+ICsJaWYgKG9sZF9kZXYtPmxlbmd0aCA9PSAwKQo+ICsJ
CXByX3dhcm4oIiVzOiBNaXNzaW5nIGJsb2NrIGluZm9ybWF0aW9uIGZvciBsb2NraW5nIHJhbmdl
ICVkXG4iLAo+ICsJCQlvbGRfZGV2LT5kaXNrX25hbWUsIG9sZF9kZXYtPmxyKTsKPiArCj4gKwly
ZXR1cm4gMDsKPiArfQo+ICsKPiAraW50IG9wYWxfcmVnaXN0ZXJfY29udChzdHJ1Y3Qgb3BhbF9k
ZXYgKm5ld19kZXYpCj4gK3sKPiArCXN0cnVjdCBvcGFsX2RldiAqb2xkX2RldjsKPiArCXVuc2ln
bmVkIGxvbmcgZmxhZ3M7Cj4gKwlpbnQgZXJyb3IgPSAwOwo+ICsKPiArCXNwaW5fbG9ja19pcnFz
YXZlKCZsaXN0X3NwaW5sb2NrLCBmbGFncyk7Cj4gKwo+ICsJb2xkX2RldiA9IGZpbmRfb3BhbF9k
ZXYobmV3X2Rldi0+YmRldiwgbmV3X2Rldi0+bHIpOwo+ICsJaWYgKCFvbGRfZGV2KSB7Cj4gKwkJ
bGlzdF9hZGRfdGFpbCgmbmV3X2Rldi0+bm9kZSwgJm9wYWxfbGlzdCk7Cj4gKwkJb2xkX2RldiA9
IG5ld19kZXY7Cj4gKwl9IGVsc2Ugewo+ICsJCWlmIChvbGRfZGV2ID09IG5ld19kZXYpCj4gKwkJ
CWVycm9yID0gMDsKPiArCQllbHNlIHsKPiArCQkJZXJyb3IgPSB1cGRhdGVfb3BhbF9kZXYob2xk
X2RldiwgbmV3X2Rldik7Cj4gKwkJCWNsZWFuX29wYWxfa2V5KG5ld19kZXYpOwo+ICsJCQlrZnJl
ZShuZXdfZGV2KTsKPiArCQl9Cj4gKwl9Cj4gKwo+ICsJaWYgKGVycm9yKQo+ICsJCWxpc3RfZGVs
KCZvbGRfZGV2LT5ub2RlKTsKPiArCj4gKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZsaXN0X3Nw
aW5sb2NrLCBmbGFncyk7Cj4gKwo+ICsJaWYgKCFlcnJvcikKPiArCQlwcl9pbmZvKCIlczogUmVn
aXN0ZXJlZCBrZXkgZm9yIGxvY2tpbmcgcmFuZ2U6ICVkXG4iLAo+ICsJCQlvbGRfZGV2LT5kaXNr
X25hbWUsIG9sZF9kZXYtPmxyKTsKPiArCj4gKwlpZiAob2xkX2Rldi0+b3Blcl9jYikKPiArCQlv
bGRfZGV2LT5vcGVyX2NiKGVycm9yLCBvbGRfZGV2KTsKPiArCj4gKwlyZXR1cm4gMDsKPiArfQo+
ICsKPiArc3RhdGljIHZvaWQgbmV4dChpbnQgZXJyb3IsIHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+
ICt7Cj4gKwlvcGFsX3N0ZXAgZnVuYyA9IGRldi0+ZnVuY3NbZGV2LT5zdGF0ZV07Cj4gKwl2b2lk
ICpjYl9kYXRhID0gZGV2LT5maW5hbF9jYl9kYXRhOwo+ICsJc2VjX2NiICpjYiA9IGRldi0+Zmlu
YWxfY2I7Cj4gKwlib29sIGRvbmUgPSBmYWxzZTsKPiArCj4gKwo+ICsJaWYgKGVycm9yIHx8ICFm
dW5jKSB7Cj4gKwkJZG9uZSA9IHRydWU7Cj4gKwkJZ290byBuZXh0X2V4aXQ7Cj4gKwl9Cj4gKwlk
ZXYtPnN0YXRlKys7Cj4gKwlkZXYtPm9wZXJfY2IgPSBuZXh0Owo+ICsJZXJyb3IgPSBmdW5jKGRl
dik7Cj4gKyBuZXh0X2V4aXQ6Cj4gKwlpZiAoZXJyb3IpIHsKPiArCQlwcl9lcnIoIiVzOiBFcnJv
ciBvbiBzdGVwIGZ1bmN0aW9uOiAlZCB3aXRoIGVycm9yICVkOiAlc1xuIiwKPiArCQkgICAgICAg
ZGV2LT5kaXNrX25hbWUsIGRldi0+c3RhdGUsIGVycm9yLAo+ICsJCSAgICAgICBvcGFsX2Vycm9y
X3RvX2h1bWFuKGVycm9yKSk7Cj4gKwo+ICsKPiArCQlhdG9taWNfZGVjKCZkZXYtPmluX3VzZSk7
Cj4gKwkJaWYgKGRldi0+ZXJyb3JfY2IpIHsKPiArCQkJZGV2LT5lcnJvcl9jYihkZXYtPmVycm9y
X2NiX2RhdGEpOwo+ICsJCQlyZXR1cm47Cj4gKwkJfQo+ICsJCWlmIChjYikKPiArCQkJY2IoZXJy
b3IsIGNiX2RhdGEpOwo+ICsKPiArCQlkZXYtPmNvbXBsZXRpb24tPmNvbXBsZXRpb25fc3RhdHVz
ID0gZXJyb3I7Cj4gKwkJY29tcGxldGUoJmRldi0+Y29tcGxldGlvbi0+Y21kX2NvbXBsZXRpb24p
Owo+ICsJfSBlbHNlIGlmICghZXJyb3IgJiYgZG9uZSkgewo+ICsJCWF0b21pY19kZWMoJmRldi0+
aW5fdXNlKTsKPiArCQlpZiAoY2IpCj4gKwkJCWNiKGVycm9yLCBjYl9kYXRhKTsKPiArCQlkZXYt
PmNvbXBsZXRpb24tPmNvbXBsZXRpb25fc3RhdHVzID0gZXJyb3I7Cj4gKwkJY29tcGxldGUoJmRl
di0+Y29tcGxldGlvbi0+Y21kX2NvbXBsZXRpb24pOwo+ICsJfQo+ICt9Cj4gKwo+ICtjb25zdCBv
cGFsX3N0ZXAgZXJyb3JfZW5kX3Nlc3Npb25bXSA9IHsKPiArCWVuZF9vcGFsX3Nlc3Npb24sCj4g
KwlOVUxMLAo+ICt9Owo+ICtzdGF0aWMgaW50IGVuZF9vcGFsX3Nlc3Npb25fZXJyb3Ioc3RydWN0
IG9wYWxfZGV2ICpkZXYpCj4gK3sKPiArCj4gKwlkZXYtPmZ1bmNzID0gZXJyb3JfZW5kX3Nlc3Np
b247Cj4gKwlkZXYtPnN0YXRlID0gMDsKPiArCWRldi0+ZXJyb3JfY2IgPSBOVUxMOwo+ICsJbmV4
dCgwLCBkZXYpOwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gK3N0YXRpYyBzdHJ1Y3Qgb3BhbF9k
ZXYgKmFsbG9jX29wYWxfZGV2KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHU4IGxyKQo+ICt7
Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKm9wYWxfZGV2Owo+ICsJc3RydWN0IHJlcXVlc3RfcXVldWUg
KnE7Cj4gKwl1bnNpZ25lZCBsb25nIGRtYV9hbGlnbjsKPiArCWNvbnN0IGNoYXIgKmRpc2tfbmFt
ZTsKPiArCXN0cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsJaW50IHJldDsKPiArCj4gKwlvcGFsX2Rl
diA9IGt6YWxsb2Moc2l6ZW9mKCpvcGFsX2RldiksIEdGUF9LRVJORUwpOwo+ICsJaWYgKCFvcGFs
X2RldikKPiArCQlyZXR1cm4gRVJSX1BUUigtRU5PTUVNKTsKPiArCj4gKwlvcGFsX2Rldi0+YmRl
diA9IGJkZXY7Cj4gKwlvcGFsX2Rldi0+bHIgPSBscjsKPiArCWNtZCA9ICZvcGFsX2Rldi0+Y21k
Owo+ICsJY21kLT5jbWQgPSBjbWQtPmNtZF9idWY7Cj4gKwljbWQtPnJlc3AgPSBjbWQtPnJlc3Bf
YnVmOwo+ICsKPiArCWRpc2tfbmFtZSA9IGJkZXYtPmJkX2Rpc2stPmRpc2tfbmFtZTsKPiArCWlm
ICghc3RybmNweShvcGFsX2Rldi0+ZGlza19uYW1lLCBkaXNrX25hbWUsIERJU0tfTkFNRV9MRU4p
KSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgcmVnaXN0ZXJpbmcgZGV2aWNlOiBjb3B5aW5nIGRp
c2sgbmFtZVxuIiwKPiArCQkgICAgICAgZGlza19uYW1lKTsKPiArCQlyZXQgPSAtRUZBVUxUOwo+
ICsJCWdvdG8gZXJyX2ZyZWVfZGV2Owo+ICsJfQo+ICsKPiArCXEgPSBiZGV2LT5iZF9xdWV1ZTsK
PiArCWRtYV9hbGlnbiA9IChxdWV1ZV9kbWFfYWxpZ25tZW50KHEpIHwgcS0+ZG1hX3BhZF9tYXNr
KSArIDE7Cj4gKwljbWQtPmNtZCA9ICh1OCAqKXJvdW5kX3VwKCh1aW50cHRyX3QpY21kLT5jbWQs
IGRtYV9hbGlnbik7Cj4gKwljbWQtPnJlc3AgPSAodTggKilyb3VuZF91cCgodWludHB0cl90KWNt
ZC0+cmVzcCwgZG1hX2FsaWduKTsKPiArCj4gKwlJTklUX0xJU1RfSEVBRCgmb3BhbF9kZXYtPm5v
ZGUpOwo+ICsJYXRvbWljX3NldCgmb3BhbF9kZXYtPmluX3VzZSwgMSk7Cj4gKwo+ICsJb3BhbF9k
ZXYtPmNvbXBsZXRpb24gPSBremFsbG9jKHNpemVvZigqb3BhbF9kZXYtPmNvbXBsZXRpb24pLAo+
ICsJCQkJICAgICAgIEdGUF9LRVJORUwpOwo+ICsKPiArCWlmICghb3BhbF9kZXYtPmNvbXBsZXRp
b24pCj4gKwkJZ290byBlcnJfZnJlZV9kZXY7Cj4gKwo+ICsJaW5pdF9jb21wbGV0aW9uKCZvcGFs
X2Rldi0+Y29tcGxldGlvbi0+Y21kX2NvbXBsZXRpb24pOwo+ICsJb3BhbF9kZXYtPmNvbXBsZXRp
b24tPmNvbXBsZXRpb25fc3RhdHVzID0gMDsKPiArCW9wYWxfZGV2LT5zdGF0ZSA9IDA7Cj4gKwo+
ICsJcmV0dXJuIG9wYWxfZGV2Owo+ICsKPiArZXJyX2ZyZWVfZGV2Ogo+ICsJa2ZyZWUob3BhbF9k
ZXYpOwo+ICsJcmV0dXJuIEVSUl9QVFIocmV0KTsKPiArfQo+ICsKPiAraW50IG9wYWxfcmVnaXN0
ZXIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IG9wYWxfa2V5ICprZXlfY21kLAo+
ICsJCSAgY29uc3Qgb3BhbF9zdGVwICpmdW5jcykKPiArewo+ICsJc3RydWN0IG9wYWxfZGV2ICpu
ZXdfZGV2ID0gTlVMTDsKPiArCXU4IGtleV9sZW4gPSBrZXlfY21kLT5rZXlfbGVuOwo+ICsJdTgg
bHIgPSBrZXlfY21kLT5scjsKPiArCXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247
Cj4gKwlpbnQgcmV0Owo+ICsKPiArCW5ld19kZXYgPSBhbGxvY19vcGFsX2RldihiZGV2LCBscik7
Cj4gKwlpZiAoSVNfRVJSKG5ld19kZXYpKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgcmVnaXN0
ZXJpbmcgZGV2aWNlOiBhbGxvY2F0aW9uXG4iLAo+ICsJCSAgICAgICBiZGV2LT5iZF9kaXNrLT5k
aXNrX25hbWUpOwo+ICsJCXJldHVybiBQVFJfRVJSKG5ld19kZXYpOwo+ICsJfQo+ICsKPiArCWlm
ICghbWVtY3B5KG5ld19kZXYtPmtleV9uYW1lLCBrZXlfY21kLT5rZXksIGtleV9sZW4pKSB7Cj4g
KwkJcHJfZXJyKCIlczogRXJyb3IgcmVnaXN0ZXJpbmcga2V5OiBjb3VsZG4ndCBjb3B5IGtleVxu
IiwKPiArCQkgICAgICAgbmV3X2Rldi0+ZGlza19uYW1lKTsKPiArCQlyZXR1cm4gLUVGQVVMVDsK
PiArCX0KPiArCj4gKwluZXdfZGV2LT5rZXlfbmFtZV9sZW4gPSBrZXlfbGVuOwo+ICsJbmV3X2Rl
di0+a2V5X3R5cGUgPSBrZXlfY21kLT5rZXlfdHlwZTsKPiArCXJldCA9IGdldF9vcGFsX2tleShu
ZXdfZGV2KTsKPiArCWlmIChyZXQpIHsKPiArCQlwcl9lcnIoIiVzOiBDb3VsZG4ndCBnZXQga2V5
OiAlZFxuIiwgbmV3X2Rldi0+ZGlza19uYW1lLCByZXQpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9
Cj4gKwo+ICsJbmV3X2Rldi0+ZnVuY3MgPSBmdW5jczsKPiArCj4gKwluZXdfZGV2LT5zdGF0ZSA9
IDA7Cj4gKwljb21wbGV0aW9uID0gbmV3X2Rldi0+Y29tcGxldGlvbjsKPiArCW5leHQoMCwgbmV3
X2Rldik7Cj4gKwo+ICsJcmV0dXJuIHdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNvbXBsZXRpb24p
Owo+ICt9Cj4gKwo+ICtzdGF0aWMgc3RydWN0IG9wYWxfZGV2ICpnZXRfcmVnaXN0ZXJlZF9vcGFs
X2RldihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LAo+ICsJCQkJCQl1OCBscikKPiArewo+ICsJ
Y29uc3QgY2hhciAqZGlza25hbWUgPSBiZGV2LT5iZF9kaXNrLT5kaXNrX25hbWU7Cj4gKwlzdHJ1
Y3Qgb3BhbF9kZXYgKml0ZXIsICpkZXYgPSBOVUxMOwo+ICsJdW5zaWduZWQgbG9uZyBmbGFnczsK
PiArCWJvb2wgaW5fdXNlID0gZmFsc2U7Cj4gKwo+ICsJc3Bpbl9sb2NrX2lycXNhdmUoJmxpc3Rf
c3BpbmxvY2ssIGZsYWdzKTsKPiArCWxpc3RfZm9yX2VhY2hfZW50cnkoaXRlciwgJm9wYWxfbGlz
dCwgbm9kZSkgewo+ICsJCWlmIChzdHJuY21wKGl0ZXItPmRpc2tfbmFtZSwgZGlza25hbWUsIERJ
U0tfTkFNRV9MRU4pKQo+ICsJCQljb250aW51ZTsKPiArCQlpZiAoaXRlci0+bHIgPT0gbHIpIHsK
PiArCQkJZGV2ID0gaXRlcjsKPiArCQkJaWYgKCFhdG9taWNfYWRkX3VubGVzcygmaXRlci0+aW5f
dXNlLCAxLCAxKSkgewo+ICsJCQkJZGV2ID0gTlVMTDsKPiArCQkJCWluX3VzZSA9IHRydWU7Cj4g
KwkJCX0KPiArCQkJYnJlYWs7Cj4gKwkJfQo+ICsJfQo+ICsKPiArCXNwaW5fdW5sb2NrX2lycXJl
c3RvcmUoJmxpc3Rfc3BpbmxvY2ssIGZsYWdzKTsKPiArCj4gKwlpZiAoIWRldikKPiArCQlyZXR1
cm4gTlVMTDsKPiArCj4gKwlkZXYtPmJkZXYgPSBiZGV2Owo+ICsJcmV0dXJuIGRldjsKPiArfQo+
ICsKPiArLyogRnJlZSB1cCB0aGUgT3BhbCBkZXYgYW5kIGl0cyBrZXlzIGR1cmluZyB0d28gc2Nl
bmFyaW9zOgo+ICsgKgo+ICsgKiAxKSBXaGVuIGEgY29tbWFuZCBpcyBjb21wbGV0ZSB0aGF0IG5v
IGxvbmdlciByZXF1aXJlcwo+ICsgKiAgICB0aGUgb3BhbCBkZXYgdG8gYmUgYXJvdW5kLgo+ICsg
KiAyKSBXaGVuIGEgY29tbWFuZCwgaW5jbHVkaW5nIE9wYWwgU2F2ZSBmYWlscyB3ZSBjbGVhbgo+
ICsgKiAgICBhbmQgZnJlZSB0aGUgb3BhbCBkZXYuCj4gKyAqCj4gKyAqICAgIElmIHdlIGZpbmQg
dGhlIG9wYWwgZGV2IHN0cnVjdHVyZSBpbiB0aGUgbGlzdCBvZgo+ICsgKiAgICBzYXZlZCBwYXNz
d29yZHMgd2Ugd2lsbCAqbm90KiByZW1vdmUgaXQuCj4gKyAqLwo+ICtzdGF0aWMgdm9pZCByZW1v
dmVfYW5kX2NsZWFuX29wYWxfZGV2KHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwlzdHJ1
Y3Qgb3BhbF9kZXYgKml0ZXI7Cj4gKwlib29sIGZvdW5kID0gZmFsc2U7Cj4gKwo+ICsJc3Bpbl9s
b2NrKCZsaXN0X3NwaW5sb2NrKTsKPiArCWxpc3RfZm9yX2VhY2hfZW50cnkoaXRlciwgJm9wYWxf
bGlzdCwgbm9kZSkgewo+ICsJCWlmIChpdGVyID09IGRldikgewo+ICsJCQlmb3VuZCA9IHRydWU7
Cj4gKwkJCWJyZWFrOwo+ICsJCX0KPiArCX0KPiArCj4gKwlzcGluX3VubG9jaygmbGlzdF9zcGlu
bG9jayk7Cj4gKwlpZiAoIWZvdW5kKSB7Cj4gKwkJY2xlYW5fb3BhbF9rZXkoZGV2KTsKPiArCQlj
bGVhbl9mdW5jdGlvbl9kYXRhKGRldik7Cj4gKwkJa2ZyZWUoZGV2KTsKPiArCX0KPiArfQo+ICsK
PiArc3RhdGljIHN0cnVjdCBvcGFsX2RldiAqZ2V0X29yX2NyZWF0ZV9vcGFsX2RldihzdHJ1Y3Qg
YmxvY2tfZGV2aWNlICpiZGV2LAo+ICsJCQkJCSAgICAgICB1OCBsciwgYm9vbCB1c2VfbmV3KQo+
ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldjsKPiArCj4gKwlpZiAodXNlX25ldykKPiArCQly
ZXR1cm4gYWxsb2Nfb3BhbF9kZXYoYmRldiwgbHIpOwo+ICsKPiArCWRldiA9IGdldF9yZWdpc3Rl
cmVkX29wYWxfZGV2KGJkZXYsIGxyKTsKPiArCWlmICghZGV2KSB7Cj4gKwkJZGV2ID0gYWxsb2Nf
b3BhbF9kZXYoYmRldiwgbHIpOwo+ICsJCWlmICghZGV2KQo+ICsJCQlyZXR1cm4gTlVMTDsKTm8g
bmVlZCBmb3IgdGhpcyBjaGVjayB3aGVuIHlvdSBhbHJlYWR5IHJldHVybiBkZXYKCgo+ICsJfQo+
ICsJcmV0dXJuIGRldjsKPiArfQpJbnN0ZWFkLCBob3cgYWJvdXQ6CnN0YXRpYyBzdHJ1Y3Qgb3Bh
bF9kZXYgKmdldF9vcl9jcmVhdGVfb3BhbF9kZXYoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwK
CQkJCQkgICAgICAgdTggbHIsIGJvb2wgdXNlX25ldykKewoJc3RydWN0IG9wYWxfZGV2ICpkZXYg
PSBOVUxMOwoKCWlmICghdXNlX25ldykKCQlkZXYgPSBnZXRfcmVnaXN0ZXJlZF9vcGFsX2Rldihi
ZGV2LCBscik7CgoJaWYgKCFkZXYpCgkJZGV2ID0gYWxsb2Nfb3BhbF9kZXYoYmRldiwgbHIpOwoK
CXJldHVybiBkZXY7Cn0KCgo+ICsKPiArc3RhdGljIHN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKnNl
dHVwX29wYWxfZGV2KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCQkJICAgICAgc3Ry
dWN0IG9wYWxfZGV2ICpkZXYsCj4gKwkJCQkJICAgICAgY29uc3Qgb3BhbF9zdGVwICpmdW5jcywK
PiArCQkJCQkgICAgICBzdHJ1Y3Qgb3BhbF9rZXkgKmtleSkKPiArewo+ICsJaW50IHJldDsKPiAr
Cj4gKwlkZXYtPmJkZXYgPSBiZGV2Owo+ICsJZGV2LT5zdGF0ZSA9IDA7Cj4gKwlkZXYtPmZ1bmNz
ID0gZnVuY3M7Cj4gKwlkZXYtPlRTTiA9IDA7Cj4gKwlkZXYtPkhTTiA9IDA7Cj4gKwlkZXYtPmZp
bmFsX2NiID0gTlVMTDsKPiArCWRldi0+ZmluYWxfY2JfZGF0YSA9IE5VTEw7Cj4gKwlkZXYtPmxy
ID0ga2V5LT5scjsKPiArCWRldi0+ZXJyb3JfY2IgPSBlbmRfb3BhbF9zZXNzaW9uX2Vycm9yOwo+
ICsJZGV2LT5lcnJvcl9jYl9kYXRhID0gZGV2Owo+ICsKPiArCWlmIChrZXkpIHsKPiArCQltZW1j
cHkoZGV2LT5rZXlfbmFtZSwga2V5LT5rZXksIGtleS0+a2V5X2xlbik7Cj4gKwkJZGV2LT5rZXlf
bmFtZV9sZW4gPSBrZXktPmtleV9sZW47Cj4gKwkJZGV2LT5rZXlfdHlwZSA9IGtleS0+a2V5X3R5
cGU7Cj4gKwo+ICsJCXJldCA9IGdldF9vcGFsX2tleShkZXYpOwo+ICsJCWlmIChyZXQpIHsKPiAr
CQkJa2ZyZWUoZGV2LT5jb21wbGV0aW9uKTsKPiArCQkJcHJfZXJyKCIlczogQ291bGRuJ3QgZ2V0
IGtleTogJWRcbiIsCj4gKwkJCSAgICAgICBkZXYtPmRpc2tfbmFtZSwgcmV0KTsKPiArCQkJcmV0
dXJuIEVSUl9QVFIocmV0KTsKPiArCQl9Cj4gKwl9Cj4gKwlkZXYtPmZ1bmNfZGF0YSA9IE5VTEw7
Cj4gKwlkZXYtPmNvbXBsZXRpb24tPmNvbXBsZXRpb25fc3RhdHVzID0gMDsKPiArCj4gKwlyZXR1
cm4gZGV2LT5jb21wbGV0aW9uOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGludGVybmFsX3NldHVw
X2xyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCSAgICAgc3RydWN0IG9wYWxfdXNl
cl9scl9zZXR1cCAqc2V0dXApCj4gK3sKPiArCXN0cnVjdCBvcGFsX2RldiAqZGV2Owo+ICsJc3Ry
dWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKPiArCXZvaWQgKmRhdGFbM10gPSB7IE5V
TEwgfTsKPiArCWNvbnN0IG9wYWxfc3RlcCBscl9mdW5jc1tdID0gewo+ICsJCW9wYWxfZGlzY292
ZXJ5MCwKPiArCQlzdGFydF9hdXRoX29wYWxfc2Vzc2lvbiwKPiArCQlzZXR1cF9sb2NraW5nX3Jh
bmdlLAo+ICsJCWdldF9hY3RpdmVfa2V5LAo+ICsJCWdlbl9rZXksCj4gKwkJZW5kX29wYWxfc2Vz
c2lvbiwKPiArCQlOVUxMLAo+ICsJfTsKPiArCWludCByZXQ7Cj4gKwo+ICsJZGV2ID0gZ2V0X29y
X2NyZWF0ZV9vcGFsX2RldihiZGV2LCBzZXR1cC0+a2V5LmxyLCB0cnVlKTsKPiArCWlmICghZGV2
KQo+ICsJCXJldHVybiAtRU5PTUVNOwo+ICsKPiArCWNvbXBsZXRpb24gPSBzZXR1cF9vcGFsX2Rl
dihiZGV2LCBkZXYsIGxyX2Z1bmNzLCAmc2V0dXAtPmtleSk7Cj4gKwlpZiAoSVNfRVJSKGNvbXBs
ZXRpb24pKSB7Cj4gKwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKPiArCQlnb3RvIGVycm9y
X3JldHVybjsKPiArCX0KPiArCj4gKwlkZXYtPmZ1bmNfZGF0YSA9IGRhdGE7Cj4gKwlkZXYtPm51
bV9mdW5jX2RhdGEgPSAzOwo+ICsJZGV2LT5mdW5jX2RhdGFbMV0gPSAmc2V0dXAtPndobzsKPiAr
CWRldi0+ZnVuY19kYXRhWzJdID0gc2V0dXA7Cj4gKwo+ICsJbmV4dCgwLCBkZXYpOwo+ICsJcmV0
ID0gd2FpdF9mb3JfY21kX2NvbXBsZXRpb24oY29tcGxldGlvbik7Cj4gKwo+ICsgZXJyb3JfcmV0
dXJuOgo+ICsJcmVtb3ZlX2FuZF9jbGVhbl9vcGFsX2RldihkZXYpOwo+ICsJcmV0dXJuIHJldDsK
PiArfQo+ICsKPiAraW50IG9wYWxfcmV2ZXJ0KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0
cnVjdCBvcGFsX2tleSAqa2V5KQo+ICt7Cj4gKwljb25zdCBvcGFsX3N0ZXAgcmV2ZXJ0X2Z1bmNz
W10gPSB7Cj4gKwkJb3BhbF9kaXNjb3ZlcnkwLAo+ICsJCXN0YXJ0X1NJREFTUF9vcGFsX3Nlc3Np
b24sCj4gKwkJcmV2ZXJ0X3RwZXIsIC8qIGNvbnRyb2xsZXIgd2lsbCB0ZXJtaW5hdGUgc2Vzc2lv
biAqLwo+ICsJCU5VTEwsCj4gKwl9Owo+ICsKPiArCXJldHVybiBvcGFsX3JlZ2lzdGVyKGJkZXYs
IGtleSwgcmV2ZXJ0X2Z1bmNzKTsKPiArfQo+ICsKPiAraW50IGFjdGl2YXRlX3VzZXIoc3RydWN0
IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IG9wYWxfYWN0aXZhdGVfdXNlciAqYWN0KQo+ICt7
Cj4gKwljb25zdCBvcGFsX3N0ZXAgYWN0X2Z1bmNzW10gPSB7Cj4gKwkJb3BhbF9kaXNjb3Zlcnkw
LAo+ICsJCXN0YXJ0X2FkbWluMUxTUF9vcGFsX3Nlc3Npb24sCj4gKwkJaW50ZXJuYWxfYWN0aXZh
dGVfdXNlciwKPiArCQllbmRfb3BhbF9zZXNzaW9uLAo+ICsJCU5VTEwKPiArCX07Cj4gKwlzdHJ1
Y3Qgb3BhbF9kZXYgKmRldjsKPiArCXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247
Cj4gKwl2b2lkICpkYXRhWzNdID0geyBOVUxMIH07Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWRldiA9
IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgYWN0LT5rZXkubHIsIHRydWUpOwo+ICsJaWYg
KCFkZXYpCj4gKwkJcmV0dXJuIC1FTk9NRU07Cj4gKwo+ICsJY29tcGxldGlvbiA9IHNldHVwX29w
YWxfZGV2KGJkZXYsIGRldiwgYWN0X2Z1bmNzLCAmYWN0LT5rZXkpOwo+ICsJaWYgKElTX0VSUihj
b21wbGV0aW9uKSkgewo+ICsJCXJldCA9IFBUUl9FUlIoY29tcGxldGlvbik7Cj4gKwkJZ290byBl
cnJvcl9yZXR1cm47Cj4gKwl9Cj4gKwo+ICsJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKPiArCWRl
di0+ZnVuY19kYXRhID0gZGF0YTsKPiArCWRldi0+ZnVuY19kYXRhWzFdID0gYWN0Owo+ICsJZGV2
LT5mdW5jX2RhdGFbMl0gPSBhY3Q7Cj4gKwo+ICsJbmV4dCgwLCBkZXYpOwo+ICsJcmV0ID0gd2Fp
dF9mb3JfY21kX2NvbXBsZXRpb24oY29tcGxldGlvbik7Cj4gKwo+ICsgZXJyb3JfcmV0dXJuOgo+
ICsJcmVtb3ZlX2FuZF9jbGVhbl9vcGFsX2RldihkZXYpOwo+ICsJcmV0dXJuIHJldDsKPiArfQo+
ICsKPiAraW50IG9wYWxfc2V0X3B3KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBv
cGFsX25ld19wdyAqcHcpCj4gKwo+ICt7Cj4gKwljb25zdCBvcGFsX3N0ZXAgcHdfZnVuY3NbXSA9
IHsKPiArCQlvcGFsX2Rpc2NvdmVyeTAsCj4gKwkJc3RhcnRfYXV0aF9vcGFsX3Nlc3Npb24sCj4g
KwkJc2V0X25ld19wdywKPiArCQllbmRfb3BhbF9zZXNzaW9uLAo+ICsJCU5VTEwKPiArCX07Cj4g
KwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldjsKPiArCXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBs
ZXRpb247Cj4gKwl2b2lkICpkYXRhWzNdID0geyBOVUxMIH07Cj4gKwlpbnQgcmV0Owo+ICsKPiAr
CWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgcHctPmN1cnJlbnRfcGluLmxyLCB0
cnVlKTsKPiArCWlmICghZGV2KQo+ICsJCXJldHVybiAtRU5PTUVNOwo+ICsKPiArCWNvbXBsZXRp
b24gPSBzZXR1cF9vcGFsX2RldihiZGV2LCBkZXYsIHB3X2Z1bmNzLCAmcHctPmN1cnJlbnRfcGlu
KTsKPiArCWlmIChJU19FUlIoY29tcGxldGlvbikpIHsKPiArCQlyZXQgPSBQVFJfRVJSKGNvbXBs
ZXRpb24pOwo+ICsJCWdvdG8gZXJyb3JfcmV0dXJuOwo+ICsJfQo+ICsKPiArCWRldi0+bnVtX2Z1
bmNfZGF0YSA9IDM7Cj4gKwlkZXYtPmZ1bmNfZGF0YSA9IGRhdGE7Cj4gKwlkZXYtPmZ1bmNfZGF0
YVsxXSA9ICh2b2lkICopICZwdy0+d2hvOwo+ICsJZGV2LT5mdW5jX2RhdGFbMl0gPSAodm9pZCAq
KSBwdzsKPiArCj4gKwluZXh0KDAsIGRldik7Cj4gKwlyZXQgPSB3YWl0X2Zvcl9jbWRfY29tcGxl
dGlvbihjb21wbGV0aW9uKTsKPiArCj4gKyBlcnJvcl9yZXR1cm46Cj4gKwlyZW1vdmVfYW5kX2Ns
ZWFuX29wYWxfZGV2KGRldik7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICtpbnQgb3BhbF9h
Y3RfbHNwX2ludChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgb3BhbF9rZXkgKmtl
eSwKPiArCQkgICAgIGNvbnN0IG9wYWxfc3RlcCAqZnVuY3MpCj4gK3sKPiArCXN0cnVjdCBvcGFs
X2RldiAqZGV2Owo+ICsJc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKPiArCWlu
dCByZXQ7Cj4gKwo+ICsJZGV2ID0gZ2V0X29yX2NyZWF0ZV9vcGFsX2RldihiZGV2LCBrZXktPmxy
LCB0cnVlKTsKPiArCWlmICghZGV2KQo+ICsJCXJldHVybiAtRU5PTUVNOwo+ICsJY29tcGxldGlv
biA9IHNldHVwX29wYWxfZGV2KGJkZXYsIGRldiwgZnVuY3MsIGtleSk7Cj4gKwlpZiAoSVNfRVJS
KGNvbXBsZXRpb24pKSB7Cj4gKwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKPiArCQlnb3Rv
IGVycm9yX3JldHVybjsKPiArCX0KPiArCj4gKwluZXh0KDAsIGRldik7Cj4gKwlyZXQgPSB3YWl0
X2Zvcl9jbWRfY29tcGxldGlvbihjb21wbGV0aW9uKTsKPiArCj4gKyBlcnJvcl9yZXR1cm46Cj4g
KwlyZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2KGRldik7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4g
Kwo+ICsKPiArc3RhdGljIGludCBvcGFsX3NhdmVfaW50ZXJuYWwoc3RydWN0IGJsb2NrX2Rldmlj
ZSAqYmRldiwKPiArCQkJICAgICAgc3RydWN0IG9wYWxfbG9ja191bmxvY2sgKmxrKQo+ICt7Cj4g
Kwl2b2lkICpmdW5jX2RhdGFbM10gPSB7IE5VTEwgfTsKPiArCXN0cnVjdCBvcGFsX2RldiAqZGV2
Owo+ICsJc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKPiArCWNvbnN0IG9wYWxf
c3RlcCBfYXV0aF9mdW5jc1tdID0gewo+ICsJCW9wYWxfZGlzY292ZXJ5MCwKPiArCQlzdGFydF9h
dXRoX29wYWxfc2Vzc2lvbiwKPiArCQlxdWVyeV9sb2NraW5nX3JhbmdlLAo+ICsJCWVuZF9vcGFs
X3Nlc3Npb24sCj4gKwkJb3BhbF9yZWdpc3Rlcl9jb250LAo+ICsJCU5VTEwKPiArCX07Cj4gKwlp
bnQgcmV0Owo+ICsKPiArCWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgbGstPmtl
eS5sciwgZmFsc2UpOwo+ICsJaWYgKCFkZXYpCj4gKwkJcmV0dXJuIC1FTk9NRU07Cj4gKwljb21w
bGV0aW9uID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBfYXV0aF9mdW5jcywgJmxrLT5rZXkp
Owo+ICsJaWYgKElTX0VSUihjb21wbGV0aW9uKSkgewo+ICsJCXJldCA9IFBUUl9FUlIoY29tcGxl
dGlvbik7Cj4gKwkJZ290byBlcnJvcl9yZXR1cm47Cj4gKwl9Cj4gKwo+ICsJZGV2LT5udW1fZnVu
Y19kYXRhID0gMzsKPiArCWRldi0+ZnVuY19kYXRhID0gZnVuY19kYXRhOwo+ICsJZGV2LT5mdW5j
X2RhdGFbMV0gPSAmbGstPmF1dGhvcml0eTsKPiArCWRldi0+bGt1bCA9ICpsazsKPiArCj4gKwlu
ZXh0KDAsIGRldik7Cj4gKwlyZXQgPSB3YWl0X2Zvcl9jbWRfY29tcGxldGlvbihjb21wbGV0aW9u
KTsKPiArCj4gKyBlcnJvcl9yZXR1cm46Cj4gKwlyZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2KGRl
dik7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGFkZF91c2VyX2xyX2lu
dGVybmFsKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCQlzdHJ1Y3Qgb3BhbF9sb2Nr
X3VubG9jayAqbGspCj4gK3sKPiArCXZvaWQgKmZ1bmNfZGF0YVszXSA9IHsgTlVMTCB9Owo+ICsJ
c3RydWN0IG9wYWxfZGV2ICpkZXY7Cj4gKwlzdHJ1Y3Qgb3BhbF9jb21wbGV0aW9uICpjb21wbGV0
aW9uOwo+ICsJY29uc3Qgb3BhbF9zdGVwIGZ1bmNzW10gPSB7Cj4gKwkJb3BhbF9kaXNjb3Zlcnkw
LAo+ICsJCXN0YXJ0X2FkbWluMUxTUF9vcGFsX3Nlc3Npb24sCj4gKwkJYWRkX3VzZXJfdG9fbHIs
Cj4gKwkJZW5kX29wYWxfc2Vzc2lvbiwKPiArCQlOVUxMCj4gKwl9Owo+ICsJaW50IHJldDsKPiAr
Cj4gKwlkZXYgPSBnZXRfb3JfY3JlYXRlX29wYWxfZGV2KGJkZXYsIGxrLT5rZXkubHIsIHRydWUp
Owo+ICsJaWYgKCFkZXYpCj4gKwkJcmV0dXJuIC1FTk9NRU07Cj4gKwljb21wbGV0aW9uID0gc2V0
dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBmdW5jcywgJmxrLT5rZXkpOwo+ICsJaWYgKElTX0VSUihj
b21wbGV0aW9uKSkgewo+ICsJCXJldCA9IFBUUl9FUlIoY29tcGxldGlvbik7Cj4gKwkJZ290byBl
cnJvcl9yZXR1cm47Cj4gKwl9Cj4gKwo+ICsJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKPiArCWRl
di0+ZnVuY19kYXRhID0gZnVuY19kYXRhOwo+ICsJZGV2LT5mdW5jX2RhdGFbMl0gPSBsazsKPiAr
Cj4gKwluZXh0KDAsIGRldik7Cj4gKwlyZXQgPSB3YWl0X2Zvcl9jbWRfY29tcGxldGlvbihjb21w
bGV0aW9uKTsKPiArCj4gKyBlcnJvcl9yZXR1cm46Cj4gKwlyZW1vdmVfYW5kX2NsZWFuX29wYWxf
ZGV2KGRldik7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGxvY2tfdW5s
b2NrX2ludGVybmFsKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCQlzdHJ1Y3Qgb3Bh
bF9sb2NrX3VubG9jayAqbGspCj4gK3sKPiArCXZvaWQgKmZ1bmNfZGF0YVszXSA9IHsgTlVMTCB9
Owo+ICsJc3RydWN0IG9wYWxfZGV2ICpkZXY7Cj4gKwlzdHJ1Y3Qgb3BhbF9jb21wbGV0aW9uICpj
b21wbGV0aW9uOwo+ICsKPiArCWNvbnN0IG9wYWxfc3RlcCB1bGtfZnVuY3NfU1VNW10gPSB7Cj4g
KwkJb3BhbF9kaXNjb3ZlcnkwLAo+ICsJCXN0YXJ0X2F1dGhfb3BhbF9zZXNzaW9uLAo+ICsJCWxv
Y2tfdW5sb2NrX2xvY2tpbmdfcmFuZ2VfU1VNLAo+ICsJCWVuZF9vcGFsX3Nlc3Npb24sCj4gKwkJ
TlVMTAo+ICsJfTsKPiArCWNvbnN0IG9wYWxfc3RlcCBfdW5sb2NrX2Z1bmNzW10gPSB7Cj4gKwkJ
b3BhbF9kaXNjb3ZlcnkwLAo+ICsJCXN0YXJ0X2F1dGhfb3BhbF9zZXNzaW9uLAo+ICsJCWxvY2tf
dW5sb2NrX2xvY2tpbmdfcmFuZ2UsCj4gKwkJZW5kX29wYWxfc2Vzc2lvbiwKPiArCQlOVUxMCj4g
Kwl9Owo+ICsJaW50IHJldDsKPiArCj4gKwlkZXYgPSBnZXRfb3JfY3JlYXRlX29wYWxfZGV2KGJk
ZXYsIGxrLT5rZXkubHIsIHRydWUpOwo+ICsJaWYgKCFkZXYpCj4gKwkJcmV0dXJuIC1FTk9NRU07
Cj4gKwo+ICsJaWYgKGxrLT5hdXRob3JpdHkuU1VNKQo+ICsJCWNvbXBsZXRpb24gPSBzZXR1cF9v
cGFsX2RldihiZGV2LCBkZXYsIHVsa19mdW5jc19TVU0sICZsay0+a2V5KTsKPiArCWVsc2UKPiAr
CQljb21wbGV0aW9uID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBfdW5sb2NrX2Z1bmNzLCAm
bGstPmtleSk7Cj4gKwo+ICsJaWYgKElTX0VSUihjb21wbGV0aW9uKSkgewo+ICsJCXJldCA9IFBU
Ul9FUlIoY29tcGxldGlvbik7Cj4gKwkJZ290byBlcnJvcl9yZXR1cm47Cj4gKwl9Cj4gKwo+ICsJ
ZGV2LT5udW1fZnVuY19kYXRhID0gMzsKPiArCWRldi0+ZnVuY19kYXRhID0gZnVuY19kYXRhOwo+
ICsJZGV2LT5mdW5jX2RhdGFbMV0gPSAmbGstPmF1dGhvcml0eTsKPiArCWRldi0+ZnVuY19kYXRh
WzJdID0gbGs7Cj4gKwo+ICsJbmV4dCgwLCBkZXYpOwo+ICsJcmV0ID0gd2FpdF9mb3JfY21kX2Nv
bXBsZXRpb24oY29tcGxldGlvbik7Cj4gKwo+ICsgZXJyb3JfcmV0dXJuOgo+ICsJcmVtb3ZlX2Fu
ZF9jbGVhbl9vcGFsX2RldihkZXYpOwo+ICsJcmV0dXJuIHJldDsKPiArfQo+ICsKPiAraW50IG9w
YWxfZXJhc2VfbG9ja2luZ19yYW5nZShzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qg
c2VkX2tleSAqa2V5KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldjsKPiArCXN0cnVjdCBv
cGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247Cj4gKwlzdHJ1Y3Qgb3BhbF9rZXkgazsKPiArCWlu
dCByZXQ7Cj4gKwljb25zdCBvcGFsX3N0ZXAgZXJhc2VfZnVuY3NbXSA9IHsKPiArCQlvcGFsX2Rp
c2NvdmVyeTAsCj4gKwkJc3RhcnRfYWRtaW4xTFNQX29wYWxfc2Vzc2lvbiwKPiArCQllcmFzZV9s
b2NraW5nX3JhbmdlLAo+ICsJCWVuZF9vcGFsX3Nlc3Npb24sCj4gKwkJTlVMTCwKPiArCX07Cj4g
Kwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrKSB7Cj4gKwkJcHJfZXJyKCJDYW4ndCBz
YXZlIHBhc3N3b3JkIGZvciBOVUxMIGJsb2NrIGRldmljZS5cbiIpOwo+ICsJCXJldHVybiAtRUlO
VkFMOwo+ICsJfQo+ICsKPiArCWlmIChjb3B5X2Zyb21fdXNlcigmaywga2V5LT5vcGFsLCBzaXpl
b2YoKmtleS0+b3BhbCkpKQo+ICsJCXJldHVybiAtRUZBVUxUOwo+ICsKPiArCWRldiA9IGdldF9v
cl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgay5sciwgdHJ1ZSk7Cj4gKwlpZiAoIWRldikKPiArCQly
ZXR1cm4gLUVOT01FTTsKPiArCj4gKwljb21wbGV0aW9uID0gc2V0dXBfb3BhbF9kZXYoYmRldiwg
ZGV2LCBlcmFzZV9mdW5jcywgJmspOwo+ICsJaWYgKElTX0VSUihjb21wbGV0aW9uKSkgewo+ICsJ
CXJldCA9IFBUUl9FUlIoY29tcGxldGlvbik7Cj4gKwkJZ290byBlcnJvcl9yZXR1cm47Cj4gKwl9
Cj4gKwo+ICsJbmV4dCgwLCBkZXYpOwo+ICsJcmV0ID0gd2FpdF9mb3JfY21kX2NvbXBsZXRpb24o
Y29tcGxldGlvbik7Cj4gKwo+ICsgZXJyb3JfcmV0dXJuOgo+ICsJcmVtb3ZlX2FuZF9jbGVhbl9v
cGFsX2RldihkZXYpOwo+ICsJcmV0dXJuIHJldDsKPiArfQo+ICtFWFBPUlRfU1lNQk9MKG9wYWxf
ZXJhc2VfbG9ja2luZ19yYW5nZSk7Cj4gKwo+ICtpbnQgb3BhbF9lbmFibGVfZGlzYWJsZV9zaGFk
b3dfbWJyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCQkgICBzdHJ1Y3Qgc2VkX2tl
eSAqa2V5KQo+ICt7Cj4gKwl2b2lkICpmdW5jX2RhdGFbNl0gPSB7IE5VTEwgfTsKPiArCXN0cnVj
dCBvcGFsX21icl9kYXRhIG1icjsKPiArCXN0cnVjdCBvcGFsX2RldiAqZGV2Owo+ICsJc3RydWN0
IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKPiArCWNvbnN0IG9wYWxfc3RlcCBtYnJfZnVu
Y3NbXSA9IHsKPiArCQlvcGFsX2Rpc2NvdmVyeTAsCj4gKwkJc3RhcnRfYWRtaW4xTFNQX29wYWxf
c2Vzc2lvbiwKPiArCQlzZXRfbWJyX2RvbmUsCj4gKwkJZW5kX29wYWxfc2Vzc2lvbiwKPiArCQlz
dGFydF9hZG1pbjFMU1Bfb3BhbF9zZXNzaW9uLAo+ICsJCXNldF9tYnJfZW5hYmxlX2Rpc2FibGUs
Cj4gKwkJZW5kX29wYWxfc2Vzc2lvbiwKPiArCQlOVUxMLAo+ICsJfTsKPiArCWludCByZXQ7Cj4g
Kwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrKSB7Cj4gKwkJcHJfZXJyKCJDYW4ndCBz
YXZlIHBhc3N3b3JkIGZvciBOVUxMIGJsb2NrIGRldmljZS5cbiIpOwo+ICsJCXJldHVybiAtRUlO
VkFMOwo+ICsJfQo+ICsKPiArCWlmIChjb3B5X2Zyb21fdXNlcigmbWJyLCBrZXktPm9wYWxfbWJy
LCBzaXplb2YoKmtleS0+b3BhbF9tYnIpKSkKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiArCj4gKwlp
ZiAobWJyLmVuYWJsZV9kaXNhYmxlICE9IE9QQUxfTUJSX0VOQUJMRSAmJgo+ICsJICAgIG1ici5l
bmFibGVfZGlzYWJsZSAhPSBPUEFMX01CUl9ESVNBQkxFKQo+ICsJCXJldHVybiAtRUlOVkFMOwo+
ICsKPiArCWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgbWJyLmtleS5sciwgdHJ1
ZSk7Cj4gKwlpZiAoIWRldikKPiArCQlyZXR1cm4gLUVOT01FTTsKPiArCj4gKwljb21wbGV0aW9u
ID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBtYnJfZnVuY3MsICZtYnIua2V5KTsKPiArCWlm
IChJU19FUlIoY29tcGxldGlvbikpIHsKPiArCQlyZXQgPSBQVFJfRVJSKGNvbXBsZXRpb24pOwo+
ICsJCWdvdG8gZXJyb3JfcmV0dXJuOwo+ICsJfQo+ICsKPiArCWRldi0+bnVtX2Z1bmNfZGF0YSA9
IDY7Cj4gKwlkZXYtPmZ1bmNfZGF0YSA9IGZ1bmNfZGF0YTsKPiArCWRldi0+ZnVuY19kYXRhWzJd
ID0gJm1ici5lbmFibGVfZGlzYWJsZTsKPiArCWRldi0+ZnVuY19kYXRhWzVdID0gJm1ici5lbmFi
bGVfZGlzYWJsZTsKPiArCj4gKwluZXh0KDAsIGRldik7Cj4gKwlyZXQgPSB3YWl0X2Zvcl9jbWRf
Y29tcGxldGlvbihjb21wbGV0aW9uKTsKPiArCj4gKyBlcnJvcl9yZXR1cm46Cj4gKwlyZW1vdmVf
YW5kX2NsZWFuX29wYWxfZGV2KGRldik7Cj4gKwlyZXR1cm4gcmV0Owo+ICsKPiArfQo+ICtFWFBP
UlRfU1lNQk9MKG9wYWxfZW5hYmxlX2Rpc2FibGVfc2hhZG93X21icik7Cj4gKwo+ICtpbnQgb3Bh
bF9zYXZlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4g
K3sKPiArCXN0cnVjdCBvcGFsX2xvY2tfdW5sb2NrIGxrdWw7Cj4gKwo+ICsJaWYgKCFiZGV2IHx8
ICFiZGV2LT5iZF9kaXNrKSB7Cj4gKwkJcHJfZXJyKCJDYW4ndCBzYXZlIHBhc3N3b3JkIGZvciBO
VUxMIGJsb2NrIGRldmljZS5cbiIpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiAr
CWlmIChjb3B5X2Zyb21fdXNlcigmbGt1bCwga2V5LT5vcGFsX2xrX3VubGssIHNpemVvZigqa2V5
LT5vcGFsKSkpCj4gKwkJcmV0dXJuIC1FRkFVTFQ7Cj4gKwo+ICsJcmV0dXJuIG9wYWxfc2F2ZV9p
bnRlcm5hbChiZGV2LCAmbGt1bCk7Cj4gK30KPiArRVhQT1JUX1NZTUJPTChvcGFsX3NhdmUpOwo+
ICsKPiAraW50IG9wYWxfYWRkX3VzZXJfdG9fbHIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwg
c3RydWN0IHNlZF9rZXkgKmtleSkKPiArewo+ICsJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgbGt1
bDsKPiArCj4gKwlpZiAoY29weV9mcm9tX3VzZXIoJmxrdWwsIGtleS0+b3BhbF9sa191bmxrLCBz
aXplb2YobGt1bCkpKQo+ICsJCXJldHVybiAtRUZBVUxUOwo+ICsKPiArCWlmICghYmRldiB8fCAh
YmRldi0+YmRfZGlzaykgewo+ICsJCXByX2VycigiQ2FuJ3QgYXNzaWduIHVzZXIgdG8gTFIgd2l0
aG91dCBiYWNraW5nIGRpc2tcbiIpOwo+ICsJCXJldHVybiAtRUZBVUxUOwo+ICsJfQo+ICsJaWYg
KGxrdWwubF9zdGF0ZSAhPSBPUEFMX1JPICYmIGxrdWwubF9zdGF0ZSAhPSBPUEFMX1JXKSB7Cj4g
KwkJcHJfZXJyKCJMb2NraW5nIHN0YXRlIHdhcyBub3QgUk8gb3IgUldcbiIpOwo+ICsJCXJldHVy
biAtRUlOVkFMOwo+ICsJfQo+ICsJaWYgKGxrdWwuYXV0aG9yaXR5LndobyA8IE9QQUxfVVNFUjEg
JiYKPiArCSAgICBsa3VsLmF1dGhvcml0eS53aG8gPiBPUEFMX1VTRVI5KSB7Cj4gKwkJcHJfZXJy
KCJBdXRob3JpdHkgd2FzIG5vdCB3aXRoaW4gdGhlIHJhbmdlIG9mIHVzZXJzOiAlZFxuIiwKPiAr
CQkgICAgICAgbGt1bC5hdXRob3JpdHkud2hvKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0K
PiArCWlmIChsa3VsLmF1dGhvcml0eS5TVU0pIHsKPiArCQlwcl9lcnIoIiVzIG5vdCBzdXBwb3J0
ZWQgaW4gU1VNLiBVc2Ugc2V0dXAgbG9ja2luZyByYW5nZVxuIiwKPiArCQkgICAgICAgX19mdW5j
X18pOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCXJldHVybiBhZGRfdXNlcl9s
cl9pbnRlcm5hbChiZGV2LCAmbGt1bCk7Cj4gK30KPiArRVhQT1JUX1NZTUJPTChvcGFsX2FkZF91
c2VyX3RvX2xyKTsKPiArCj4gK2ludCBvcGFsX3JldmVydHRwZXIoc3RydWN0IGJsb2NrX2Rldmlj
ZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKPiArewo+ICsJc3RydWN0IG9wYWxfa2V5IGs7
Cj4gKwo+ICsJaWYgKGNvcHlfZnJvbV91c2VyKCZrLCBrZXktPm9wYWwsIHNpemVvZigqa2V5LT5v
cGFsKSkpCj4gKwkJcmV0dXJuIC1FRkFVTFQ7Cj4gKwo+ICsJcmV0dXJuIG9wYWxfcmV2ZXJ0KGJk
ZXYsICZrKTsKPiArfQo+ICtFWFBPUlRfU1lNQk9MKG9wYWxfcmV2ZXJ0dHBlcik7Cj4gKwo+ICtp
bnQgb3BhbF9sb2NrX3VubG9jayhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2Vk
X2tleSAqa2V5KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9sb2NrX3VubG9jayBrOwo+ICsKPiArCWlm
IChjb3B5X2Zyb21fdXNlcigmaywga2V5LT5vcGFsX2xrX3VubGssIHNpemVvZigqa2V5LT5vcGFs
X2xrX3VubGspKSkKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiArCj4gKwlpZiAoay5hdXRob3JpdHku
d2hvIDwgT1BBTF9BRE1JTjEgfHwgay5hdXRob3JpdHkud2hvID49IE9QQUxfVVNFUjkpClNob3Vs
ZCB0aGlzIGJlID4gT1BBTF9VU0VSOSA/CgoKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCj4gKwly
ZXR1cm4gbG9ja191bmxvY2tfaW50ZXJuYWwoYmRldiwgJmspOwo+ICt9Cj4gK0VYUE9SVF9TWU1C
T0wob3BhbF9sb2NrX3VubG9jayk7Cj4gKwo+ICtpbnQgb3BhbF90YWtlX293bmVyc2hpcChzdHJ1
Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwlzdHJ1
Y3Qgb3BhbF9rZXkgazsKPiArCWNvbnN0IG9wYWxfc3RlcCBvd25lcl9mdW5jc1tdID0gewo+ICsJ
CW9wYWxfZGlzY292ZXJ5MCwKPiArCQlzdGFydF9hbnlib2R5QVNQX29wYWxfc2Vzc2lvbiwKPiAr
CQlnZXRfbXNpZF9jcGluX3BpbiwKPiArCQllbmRfb3BhbF9zZXNzaW9uLAo+ICsJCXN0YXJ0X1NJ
REFTUF9vcGFsX3Nlc3Npb24sCj4gKwkJc2V0X3NpZF9jcGluX3BpbiwKPiArCQllbmRfb3BhbF9z
ZXNzaW9uLAo+ICsJCU5VTEwKPiArCX07Cj4gKwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9k
aXNrKSB7Cj4gKwkJcHJfZXJyKCJDYW4ndCBzYXZlIHBhc3N3b3JkIGZvciBOVUxMIGJsb2NrIGRl
dmljZS5cbiIpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCWlmIChjb3B5X2Zy
b21fdXNlcigmaywga2V5LT5vcGFsLCBzaXplb2YoKmtleS0+b3BhbCkpKQo+ICsJCXJldHVybiAt
RUZBVUxUOwo+ICsKPiArCXJldHVybiBvcGFsX3JlZ2lzdGVyKGJkZXYsICZrLCBvd25lcl9mdW5j
cyk7Cj4gK30KPiArRVhQT1JUX1NZTUJPTChvcGFsX3Rha2Vfb3duZXJzaGlwKTsKPiArCj4gK2lu
dCBvcGFsX2FjdGl2YXRlX2xzcChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2Vk
X2tleSAqa2V5KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9rZXkgazsKPiArCWNvbnN0IG9wYWxfc3Rl
cCBhY3RpdmVfZnVuY3NbXSA9IHsKPiArCQlvcGFsX2Rpc2NvdmVyeTAsCj4gKwkJc3RhcnRfU0lE
QVNQX29wYWxfc2Vzc2lvbiwgLyogT3BlbiBzZXNzaW9uIGFzIFNJRCBhdXRoICovCj4gKwkJZ2V0
X2xzcF9saWZlY3ljbGUsCj4gKwkJYWN0aXZhdGVfbHNwLAo+ICsJCWVuZF9vcGFsX3Nlc3Npb24s
Cj4gKwkJTlVMTAo+ICsJfTsKPiArCj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2spIHsK
PiArCQlwcl9lcnIoIkNhbid0IHNhdmUgcGFzc3dvcmQgZm9yIE5VTEwgYmxvY2sgZGV2aWNlLlxu
Iik7Cj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwl9Cj4gKwo+ICsJaWYgKGNvcHlfZnJvbV91c2Vy
KCZrLCBrZXktPm9wYWwsIHNpemVvZigqa2V5LT5vcGFsKSkpCj4gKwkJcmV0dXJuIC1FRkFVTFQ7
Cj4gKwo+ICsJcmV0dXJuIG9wYWxfYWN0X2xzcF9pbnQoYmRldiwgJmssIGFjdGl2ZV9mdW5jcyk7
Cj4gK30KPiArRVhQT1JUX1NZTUJPTChvcGFsX2FjdGl2YXRlX2xzcCk7Cj4gKwo+ICtpbnQgb3Bh
bF9zZXR1cF9sb2NraW5nX3JhbmdlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBz
ZWRfa2V5ICpwdykKPiArewo+ICsJc3RydWN0IG9wYWxfdXNlcl9scl9zZXR1cCBrOwo+ICsKPiAr
CWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzaykgewo+ICsJCXByX2VycigiQ2FuJ3Qgc2F2ZSBw
YXNzd29yZCBmb3IgTlVMTCBibG9jayBkZXZpY2UuXG4iKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsK
PiArCX0KPiArCj4gKwlpZiAoY29weV9mcm9tX3VzZXIoJmssIHB3LT5vcGFsX2xycywgc2l6ZW9m
KCpwdy0+b3BhbF9scnMpKSkKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiArCj4gKwlyZXR1cm4gaW50
ZXJuYWxfc2V0dXBfbHIoYmRldiwgJmspOwo+ICt9Cj4gKwo+ICtpbnQgb3BhbF9zZXRfbmV3X3B3
KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICpwdykKPiArewo+ICsJ
c3RydWN0IG9wYWxfbmV3X3B3IGs7Cj4gKwo+ICsJaWYgKHB3LT5zZWRfdHlwZSAhPSBPUEFMX1BX
KQo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsKPiArCWlmIChjb3B5X2Zyb21fdXNlcigmaywgcHct
Pm9wYWxfcHcsIHNpemVvZigqcHctPm9wYWxfcHcpKSkKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiAr
Cj4gKwlpZiAoay53aG8ud2hvIDwgT1BBTF9BRE1JTjEgfHwgay53aG8ud2hvID4gT1BBTF9VU0VS
OSkKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCj4gKwlyZXR1cm4gb3BhbF9zZXRfcHcoYmRldiwg
JmspOwo+ICt9Cj4gK0VYUE9SVF9TWU1CT0wob3BhbF9zZXRfbmV3X3B3KTsKPiArCj4gK2ludCBv
cGFsX2FjdGl2YXRlX3VzZXIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9r
ZXkgKnB3KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9hY3RpdmF0ZV91c2VyIGs7Cj4gKwo+ICsJaWYg
KHB3LT5zZWRfdHlwZSAhPSBPUEFMX0FDVF9VU1IpIHsKPiArCQlwcl9lcnIoIlNlZCB0eXBlIHdh
cyBub3QgYWN0IHVzZXJcbiIpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCWlm
IChjb3B5X2Zyb21fdXNlcigmaywgcHctPm9wYWxfYWN0LCBzaXplb2YoKnB3LT5vcGFsX2FjdCkp
KSB7Cj4gKwkJcHJfZXJyKCJjb3B5IGZyb20gdXNlciBlcnJvclxuIik7Cj4gKwkJcmV0dXJuIC1F
RkFVTFQ7Cj4gKwl9Cj4gKwo+ICsJLyogV2UgY2FuJ3QgYWN0aXZhdGUgQWRtaW4xIGl0J3MgYWN0
aXZlIGFzIG1hbnVmYWN0dXJlZCAqLwo+ICsJaWYgKGsud2hvLndobyA8IE9QQUxfVVNFUjEgJiYg
ay53aG8ud2hvID4gT1BBTF9VU0VSOSkgewo+ICsJCXByX2VycigiV2hvIHdhcyBub3QgYSB2YWxp
ZCB1c2VyOiAlZCBcbiIsIGsud2hvLndobyk7Cj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwl9Cj4g
Kwo+ICsJcmV0dXJuIGFjdGl2YXRlX3VzZXIoYmRldiwgJmspOwo+ICsKPiArfQo+ICtFWFBPUlRf
U1lNQk9MKG9wYWxfYWN0aXZhdGVfdXNlcik7Cj4gKwo+ICtpbnQgb3BhbF91bmxvY2tfZnJvbV9z
dXNwZW5kKHN0cnVjdCBvcGFsX3N1c3BlbmRfdW5sayAqZGF0YSkKPiArewo+ICsJY29uc3QgY2hh
ciAqZGlza25hbWUgPSBkYXRhLT5uYW1lOwo+ICsJc3RydWN0IG9wYWxfZGV2ICppdGVyLCAqZGV2
ID0gTlVMTDsKPiArCXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247Cj4gKwl2b2lk
ICpmdW5jX2RhdGFbM10gPSB7IE5VTEwgfTsKPiArCWNvbnN0IG9wYWxfc3RlcCBfdW5sb2NrX2Z1
bmNzX1NVTVtdID0gewo+ICsJCW9wYWxfZGlzY292ZXJ5MCwKPiArCQlzdGFydF9hdXRoX29wYWxf
c2Vzc2lvbiwKPiArCQlsb2NrX3VubG9ja19sb2NraW5nX3JhbmdlLApEaWQgeW91IG1lYW4gdG8g
dXNlIGxvY2tfdW5sb2NrX2xvY2tpbmdfcmFuZ2VfU1VNID8KQ2FuIHdlIHB1bGwgdGhlc2UgdHdv
IGFycmF5cyBvdXQgc2luY2UgdGhleSBhcmUgcmVxdWlyZWQgZm9yIGJvdGggdGhpcwpmdW5jdGlv
biBhbmQgbG9ja191bmxvY2tfaW50ZXJuYWwgPwoKCj4gKwkJZW5kX29wYWxfc2Vzc2lvbiwKPiAr
CQlOVUxMCj4gKwl9Owo+ICsJY29uc3Qgb3BhbF9zdGVwIF91bmxvY2tfZnVuY3NbXSA9IHsKPiAr
CQlvcGFsX2Rpc2NvdmVyeTAsCj4gKwkJc3RhcnRfYXV0aF9vcGFsX3Nlc3Npb24sCj4gKwkJbG9j
a191bmxvY2tfbG9ja2luZ19yYW5nZSwKPiArCQllbmRfb3BhbF9zZXNzaW9uLAo+ICsJCU5VTEwK
PiArCX07Cj4gKwo+ICsKPiArCXNwaW5fbG9jaygmbGlzdF9zcGlubG9jayk7Cj4gKwlsaXN0X2Zv
cl9lYWNoX2VudHJ5KGl0ZXIsICZvcGFsX2xpc3QsIG5vZGUpIHsKPiArCQlpZiAoc3RybmNtcChp
dGVyLT5kaXNrX25hbWUsIGRpc2tuYW1lLCBESVNLX05BTUVfTEVOKSkgewo+ICsJCQlwcl9lcnIo
Iml0ZXJkaXNrIHdhcyAlcyBhbmQgZGlza25hbWUgaXMgJXNcbiIsCj4gKwkJCSAgICAgICBpdGVy
LT5kaXNrX25hbWUsIGRpc2tuYW1lKTsKPiArCQkJY29udGludWU7Cj4gKwkJfQo+ICsJCWlmIChh
dG9taWNfYWRkX3VubGVzcygmaXRlci0+aW5fdXNlLCAxLCAxKSkgewo+ICsJCQlkZXYgPSBpdGVy
Owo+ICsJCQlkZXYtPmZ1bmNfZGF0YSA9IGZ1bmNfZGF0YTsKPiArCQkJZGV2LT5yZXN1bWVfZnJv
bV9zdXNwZW5kID0gdHJ1ZTsKPiArCQkJZGV2LT5yZXN1bWVfZGF0YSA9IGRhdGE7Cj4gKwkJCWRl
di0+ZmluYWxfY2IgPSB1bmxvY2tfc3VzcGVuZF9maW5hbDsKPiArCQkJZGV2LT5maW5hbF9jYl9k
YXRhID0gZGV2Owo+ICsJCQlkZXYtPmVycm9yX2NiID0gZW5kX29wYWxfc2Vzc2lvbl9lcnJvcjsK
PiArCQkJZGV2LT5lcnJvcl9jYl9kYXRhID0gZGV2Owo+ICsJCQlkZXYtPnN0YXRlID0gMDsKPiAr
CQkJaWYgKGRldi0+bGt1bC5hdXRob3JpdHkuU1VNKQo+ICsJCQkJZGV2LT5mdW5jcyA9IF91bmxv
Y2tfZnVuY3NfU1VNOwo+ICsJCQllbHNlCj4gKwkJCQlkZXYtPmZ1bmNzID0gX3VubG9ja19mdW5j
czsKPiArCQkJZGV2LT5UU04gPSAwOwo+ICsJCQlkZXYtPkhTTiA9IDA7Cj4gKwkJCWRldi0+ZnVu
Y19kYXRhWzJdID0gJmRldi0+bGt1bDsKPiArCQkJZGV2LT5mdW5jX2RhdGFbMV0gPSAmZGV2LT5s
a3VsLmF1dGhvcml0eTsKPiArCQkJY29tcGxldGlvbiA9IGRldi0+Y29tcGxldGlvbjsKPiArCQkJ
bmV4dCgwLCBkZXYpOwo+ICsJCQl3YWl0X2Zvcl9jbWRfY29tcGxldGlvbihjb21wbGV0aW9uKTsK
PiArCQl9Cj4gKwl9Cj4gKwlzcGluX3VubG9jaygmbGlzdF9zcGlubG9jayk7Cj4gKwo+ICsJaWYg
KCFkZXYpCj4gKwkJcmV0dXJuIC1FTk9ERVY7Cj4gKwlyZXR1cm4gMDsKPiArfQo+ICtFWFBPUlRf
U1lNQk9MKG9wYWxfdW5sb2NrX2Zyb21fc3VzcGVuZCk7Cj4gZGlmZiAtLWdpdCBhL2xpYi9zZWQt
b3BhbF9pbnRlcm5hbC5oIGIvbGliL3NlZC1vcGFsX2ludGVybmFsLmgKPiBuZXcgZmlsZSBtb2Rl
IDEwMDY0NAo+IGluZGV4IDAwMDAwMDAuLmM5ZDM4ODMKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIv
bGliL3NlZC1vcGFsX2ludGVybmFsLmgKPiBAQCAtMCwwICsxLDU4NiBAQAo+ICsvKgo+ICsgKiBD
b3B5cmlnaHQgwqkgMjAxNiBJbnRlbCBDb3Jwb3JhdGlvbgo+ICsgKgo+ICsgKiBQZXJtaXNzaW9u
IGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5p
bmcgYQo+ICsgKiBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRh
dGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLAo+ICsgKiB0byBkZWFsIGluIHRoZSBTb2Z0d2Fy
ZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uCj4gKyAq
IHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmli
dXRlLCBzdWJsaWNlbnNlLAo+ICsgKiBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJl
LCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUKPiArICogU29mdHdhcmUgaXMgZnVy
bmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoKPiAr
ICoKPiArICogVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBu
b3RpY2UgKGluY2x1ZGluZyB0aGUgbmV4dAo+ICsgKiBwYXJhZ3JhcGgpIHNoYWxsIGJlIGluY2x1
ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlCj4gKyAqIFNv
ZnR3YXJlLgo+ICsgKgo+ICsgKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lU
SE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgo+ICsgKiBJTVBMSUVELCBJTkNM
VURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElU
WSwKPiArICogRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdF
TUVOVC4gIElOIE5PIEVWRU5UIFNIQUxMCj4gKyAqIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBI
T0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSCj4gKyAqIExJ
QUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJX
SVNFLCBBUklTSU5HCj4gKyAqIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhF
IFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MKPiArICogSU4gVEhFIFNPRlRX
QVJFLgo+ICsgKgo+ICsgKiBBdXRob3I6Cj4gKyAqICAgIFJhZmFlbCBBbnRvZ25vbGxpIDxyYWZh
ZWwuYW50b2dub2xsaUBpbnRlbC5jb20+Cj4gKyAqICAgIFNjb3R0ICBCYXVlciAgICAgIDxzY290
dC5iYXVlckBpbnRlbC5jb20+Cj4gKyAqLwo+ICsKPiArI2lmbmRlZiBfTlZNRV9PUEFMX0lOVEVS
TkFMX0gKPiArI2RlZmluZSBfTlZNRV9PUEFMX0lOVEVSTkFMX0gKPiArCj4gKyNpbmNsdWRlIDxs
aW51eC9rZXktdHlwZS5oPgo+ICsjaW5jbHVkZSA8a2V5cy91c2VyLXR5cGUuaD4KPiArCj4gKyNk
ZWZpbmUgRFRBRVJST1JfTk9fTUVUSE9EX1NUQVRVUyAweDg5Cj4gKwo+ICtzdGF0aWMgY29uc3Qg
Y2hhciAqb3BhbF9lcnJvcnNbMTldID0gewpSZW1vdmUgdGhlIDE5IHNvIGl0J3MganVzdCBvcGFs
X2Vycm9yc1tdIChkb2VzbnQgc2lsZW50bHkgdHJ1bmNhdGUgYW55Cm5ldyBhZGRpdGlvbnMpCgoK
PiArCSJTdWNjZXNzIiwKPiArCSJOb3QgQXV0aG9yaXplZCIsCj4gKwkiVW5rbm93biBFcnJvciIs
Cj4gKwkiU1AgQnVzeSIsCj4gKwkiU1AgRmFpbGVkIiwKPiArCSJTUCBEaXNhYmxlZCIsCj4gKwki
U1AgRnJvemVuIiwKPiArCSJObyBTZXNzaW9ucyBBdmFpbGFibGUiLAo+ICsJIlVuaXF1ZW5lc3Mg
Q29uZmxpY3QiLAo+ICsJIkluc3VmZmljaWVudCBTcGFjZSIsCj4gKwkiSW5zdWZmaWNpZW50IFJv
d3MiLAo+ICsJIkludmFsaWQgRnVuY3Rpb24iLAo+ICsJIkludmFsaWQgUGFyYW1ldGVyIiwKPiAr
CSJJbnZhbGlkIFJlZmVyZW5jZSIsCj4gKwkiVW5rbm93biBFcnJvciIsCj4gKwkiVFBFUiBNYWxm
dW5jdGlvbiIsCj4gKwkiVHJhbnNhY3Rpb24gRmFpbHVyZSIsCj4gKwkiUmVzcG9uc2UgT3ZlcmZs
b3ciLAo+ICsJIkF1dGhvcml0eSBMb2NrZWQgT3V0IiwKPiArfTsKPiArCj4gK3N0YXRpYyBjb25z
dCBjaGFyICpvcGFsX2Vycm9yX3RvX2h1bWFuKGludCBlcnJvcikKPiArewo+ICsJaWYgKGVycm9y
ID09IDB4M2YpCj4gKwkJcmV0dXJuICJGYWlsZWQiOwo+ICsKPiArCWlmIChlcnJvciA+PSBzaXpl
b2Yob3BhbF9lcnJvcnMpIHx8IGVycm9yIDwgMCkKWW91IHdhbnQgc2l6ZW9mKG9wYWxfZXJyb3Jz
KS9zaXplb2YoKm9wYWxfZXJyb3JzKSBoZXJlLCBidXQgeW91IGNhbiBqdXN0CnVzZSB0aGUgQVJS
QVlfU0laRSBtYWNybyBpbnN0ZWFkCgoKPiArCQlyZXR1cm4gIlVua25vd24gRXJyb3IiOwo+ICsK
PiArCXJldHVybiBvcGFsX2Vycm9yc1tlcnJvcl07Cj4gK30KPiArCj4gKy8qIFVzZXIgSURzIHVz
ZWQgaW4gdGhlIFRDRyBzdG9yYWdlIFNTQ3MgKi8KPiArc3RhdGljIGNvbnN0IHU4IE9QQUxVSURb
XVs4XSA9IHsKPiArCS8qIHVzZXJzICovCj4gKwo+ICsJLyogc2Vzc2lvbiBtYW5hZ2VtZW50ICAq
Lwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweGZmfSwK
PiArCS8qIHNwZWNpYWwgInRoaXNTUCIgc3ludGF4ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAs
IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDEgfSwKPiArCS8qIEFkbWluaXN0cmF0aXZlIFNQ
ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDIsIDB4MDUsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDEg
fSwKPiArCS8qIExvY2tpbmcgU1AgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMiwgMHgwNSwgMHgw
MCwgMHgwMCwgMHgwMCwgMHgwMiB9LAo+ICsJLyogRU5URVJQUklTRSBMb2NraW5nIFNQICAqLwo+
ICsJeyAweDAwLCAweDAwLCAweDAyLCAweDA1LCAweDAwLCAweDAxLCAweDAwLCAweDAxIH0sCj4g
KwkvKiBhbnlib2R5ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDksIDB4MDAsIDB4MDAs
IDB4MDAsIDB4MDEgfSwKPiArCS8qIFNJRCAqLwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDA5
LCAweDAwLCAweDAwLCAweDAwLCAweDA2IH0sCj4gKwkvKiBBRE1JTjEgKi8KPiArCXsgMHgwMCwg
MHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgwMSwgMHgwMCwgMHgwMSB9LAo+ICsJLyogVVNFUjEg
Ki8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgwMywgMHgwMCwgMHgwMSB9
LAo+ICsJLyogVVNFUjIgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgw
MywgMHgwMCwgMHgwMiB9LAo+ICsJLyogUFNJRCB1c2VyICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4
MDAsIDB4MDksIDB4MDAsIDB4MDEsIDB4ZmYsIDB4MDEgfSwKPiArCS8qIEJhbmRNYXN0ZXIgMCAq
Lwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDA5LCAweDAwLCAweDAwLCAweDgwLCAweDAxIH0s
Cj4gKwkgLyogRXJhc2VNYXN0ZXIgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgw
MCwgMHgwMCwgMHg4NCwgMHgwMSB9LAo+ICsKPiArCS8qIHRhYmxlcyAqLwo+ICsKPiArCS8qIExv
Y2tpbmdfR2xvYmFsUmFuZ2UgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwOCwgMHgwMiwgMHgwMCwg
MHgwMCwgMHgwMCwgMHgwMSB9LAo+ICsJLyogQUNFX0xvY2tpbmdfUmFuZ2VfU2V0X1JkTG9ja2Vk
IFVJRCAqLwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDA4LCAweDAwLCAweDAzLCAweEUwLCAw
eDAxIH0sCj4gKwkvKiBBQ0VfTG9ja2luZ19SYW5nZV9TZXRfV3JMb2NrZWQgVUlEICovCj4gKwl7
IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDgsIDB4MDAsIDB4MDMsIDB4RTgsIDB4MDEgfSwKPiArCS8q
IE1CUiBDb250cm9sICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDgsIDB4MDMsIDB4MDAsIDB4MDAs
IDB4MDAsIDB4MDEgfSwKPiArCS8qIFNoYWRvdyBNQlIgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgw
OCwgMHgwNCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCB9LAo+ICsJLyogQVVUSE9SSVRZX1RBQkxF
ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDksIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDB9
LAo+ICsJLyogQ19QSU5fVEFCTEUgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwQiwgMHgw
MCwgMHgwMCwgMHgwMCwgMHgwMH0sCj4gKwkvKiBPUEFMIExvY2tpbmcgSW5mbyAqLwo+ICsJeyAw
eDAwLCAweDAwLCAweDA4LCAweDAxLCAweDAwLCAweDAwLCAweDAwLCAweDAxIH0sCj4gKwkvKiBF
bnRlcnByaXNlIExvY2tpbmcgSW5mbyAqLwo+ICsJeyAweDAwLCAweDAwLCAweDA4LCAweDAxLCAw
eDAwLCAweDAwLCAweDAwLCAweDAwIH0sCj4gKwo+ICsJLyogQ19QSU5fVEFCTEUgb2JqZWN0IElE
J3MgKi8KPiArCj4gKwkvKiBDX1BJTl9NU0lEICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4
MEIsIDB4MDAsIDB4MDAsIDB4ODQsIDB4MDJ9LAo+ICsJLyogQ19QSU5fU0lEICovCj4gKwl7IDB4
MDAsIDB4MDAsIDB4MDAsIDB4MEIsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDF9LAo+ICsJIC8qIENf
UElOX0FETUlOMSAqLwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDBCLCAweDAwLCAweDAxLCAw
eDAwLCAweDAxfSwKPiArCj4gKwkvKiBoYWxmIFVJRCdzIChvbmx5IGZpcnN0IDQgYnl0ZXMgdXNl
ZCkgKi8KPiArCj4gKwkvKiBIYWxmLVVJRCDigJMgQXV0aG9yaXR5X29iamVjdF9yZWYgKi8KPiAr
CXsgMHgwMCwgMHgwMCwgMHgwQywgMHgwNSwgMHhmZiwgMHhmZiwgMHhmZiwgMHhmZiB9LAo+ICsJ
LyogSGFsZi1VSUQg4oCTIEJvb2xlYW4gQUNFICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDQsIDB4
MEUsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYgfSwKPiArCj4gKwkvKiBzcGVjaWFsIHZhbHVlIGZv
ciBvbWl0dGVkIG9wdGlvbmFsIHBhcmFtZXRlciAqLwo+ICsKPiArCS8qIEhFWEZGIGZvciBvbWl0
dGVkICovCj4gKwl7IDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4
ZmZ9LAo+ICt9Owo+ICtzdGF0aWMgY29uc3Qgc2l6ZV90IE9QQUxfVUlEX0xFTkdUSCA9IDg7Cj4g
K3N0YXRpYyBjb25zdCBzaXplX3QgT1BBTF9NU0lEX0tFWUxFTiA9IDE1Owo+ICtzdGF0aWMgY29u
c3Qgc2l6ZV90IE9QQUxfVUlEX0xFTkdUSF9IQUxGID0gNDsKPiArCj4gKwo+ICsvKiBFbnVtIHRv
IGluZGV4IE9QQUxVSUQgYXJyYXkgKi8KPiArZW51bSBPUEFMX1VJRCB7Cj4gKwkvKiB1c2VycyAq
Lwo+ICsJT1BBTF9TTVVJRF9VSUQsCj4gKwlPUEFMX1RISVNTUF9VSUQsCj4gKwlPUEFMX0FETUlO
U1BfVUlELAo+ICsJT1BBTF9MT0NLSU5HU1BfVUlELAo+ICsJT1BBTF9FTlRFUlBSSVNFX0xPQ0tJ
TkdTUF9VSUQsCj4gKwlPUEFMX0FOWUJPRFlfVUlELAo+ICsJT1BBTF9TSURfVUlELAo+ICsJT1BB
TF9BRE1JTjFfVUlELAo+ICsJT1BBTF9VU0VSMV9VSUQsCj4gKwlPUEFMX1VTRVIyX1VJRCwKPiAr
CU9QQUxfUFNJRF9VSUQsCj4gKwlPUEFMX0VOVEVSUFJJU0VfQkFORE1BU1RFUjBfVUlELAo+ICsJ
T1BBTF9FTlRFUlBSSVNFX0VSQVNFTUFTVEVSX1VJRCwKPiArCS8qIHRhYmxlcyAqLwo+ICsJT1BB
TF9MT0NLSU5HUkFOR0VfR0xPQkFMLAo+ICsJT1BBTF9MT0NLSU5HUkFOR0VfQUNFX1JETE9DS0VE
LAo+ICsJT1BBTF9MT0NLSU5HUkFOR0VfQUNFX1dSTE9DS0VELAo+ICsJT1BBTF9NQlJDT05UUk9M
LAo+ICsJT1BBTF9NQlIsCj4gKwlPUEFMX0FVVEhPUklUWV9UQUJMRSwKPiArCU9QQUxfQ19QSU5f
VEFCTEUsCj4gKwlPUEFMX0xPQ0tJTkdfSU5GT19UQUJMRSwKPiArCU9QQUxfRU5URVJQUklTRV9M
T0NLSU5HX0lORk9fVEFCTEUsCj4gKwkvKiBDX1BJTl9UQUJMRSBvYmplY3QgSUQncyAqLwo+ICsJ
T1BBTF9DX1BJTl9NU0lELAo+ICsJT1BBTF9DX1BJTl9TSUQsCj4gKwlPUEFMX0NfUElOX0FETUlO
MSwKPiArCS8qIGhhbGYgVUlEJ3MgKG9ubHkgZmlyc3QgNCBieXRlcyB1c2VkKSAqLwo+ICsJT1BB
TF9IQUxGX1VJRF9BVVRIT1JJVFlfT0JKX1JFRiwKPiArCU9QQUxfSEFMRl9VSURfQk9PTEVBTl9B
Q0UsCj4gKwkvKiBvbWl0dGVkIG9wdGlvbmFsIHBhcmFtZXRlciAqLwo+ICsJT1BBTF9VSURfSEVY
RkYsCj4gK307Cj4gKwo+ICsvKgo+ICsgKiBUQ0cgU3RvcmFnZSBTU0MgTWV0aG9kcy4KPiArICov
Cj4gK3N0YXRpYyBjb25zdCB1OCBPUEFMTUVUSE9EW11bOF0gPSB7Cj4gKwkvKiBQcm9wZXJ0aWVz
ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4ZmYsIDB4MDEg
fSwKPiArCS8qIFNUQVJUU0VTU0lPTiAqLwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDAwLCAw
eDAwLCAweDAwLCAweGZmLCAweDAyIH0sCj4gKwkvKiBSZXZlcnQgKi8KPiArCXsgMHgwMCwgMHgw
MCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMiwgMHgwMiB9LAo+ICsJLyogQWN0aXZhdGUg
Ki8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMiwgMHgwMyB9
LAo+ICsJLyogRW50ZXJwcmlzZSBHZXQgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwg
MHgwMCwgMHgwMCwgMHgwMCwgMHgwNiB9LAo+ICsJLyogRW50ZXJwcmlzZSBTZXQgKi8KPiArCXsg
MHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNyB9LAo+ICsJLyog
TkVYVCAqLwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAw
eDA4IH0sCj4gKwkvKiBFbnRlcnByaXNlIEF1dGhlbnRpY2F0ZSAqLwo+ICsJeyAweDAwLCAweDAw
LCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAweDBjIH0sCj4gKwkvKiBHZXRBQ0wgKi8K
PiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwZCB9LAo+
ICsJLyogR2VuS2V5ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAs
IDB4MDAsIDB4MTAgfSwKPiArCS8qIHJldmVydFNQICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAs
IDB4MDYsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MTEgfSwKPiArCS8qIEdldCAqLwo+ICsJeyAweDAw
LCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAweDE2IH0sCj4gKwkvKiBTZXQg
Ki8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgxNyB9
LAo+ICsJLyogQXV0aGVudGljYXRlICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4
MDAsIDB4MDAsIDB4MDAsIDB4MWMgfSwKPiArCS8qIFJhbmRvbSAqLwo+ICsJeyAweDAwLCAweDAw
LCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDA2LCAweDAxIH0sCj4gKwkvKiBFcmFzZSAqLwo+
ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDA4LCAweDAzIH0sCj4g
K307Cj4gK3N0YXRpYyBjb25zdCBzaXplX3QgT1BBTF9NRVRIT0RfTEVOR1RIID0gODsKPiArCj4g
Ky8qIEVudW0gZm9yIGluZGV4aW5nIHRoZSBPUEFMTUVUSE9EIGFycmF5ICovCj4gK2VudW0gT1BB
TF9NRVRIT0Qgewo+ICsJT1BBTF9QUk9QRVJUSUVTLAo+ICsJT1BBTF9TVEFSVFNFU1NJT04sCj4g
KwlPUEFMX1JFVkVSVCwKPiArCU9QQUxfQUNUSVZBVEUsCj4gKwlPUEFMX0VHRVQsCj4gKwlPUEFM
X0VTRVQsCj4gKwlPUEFMX05FWFQsCj4gKwlPUEFMX0VBVVRIRU5USUNBVEUsCj4gKwlPUEFMX0dF
VEFDTCwKPiArCU9QQUxfR0VOS0VZLAo+ICsJT1BBTF9SRVZFUlRTUCwKPiArCU9QQUxfR0VULAo+
ICsJT1BBTF9TRVQsCj4gKwlPUEFMX0FVVEhFTlRJQ0FURSwKPiArCU9QQUxfUkFORE9NLAo+ICsJ
T1BBTF9FUkFTRSwKPiArfTsKPiArCj4gK2VudW0gT1BBTF9SRVNQT05TRV9UT0tFTiB7Cj4gKwlP
UEFMX0RUQV9UT0tFTklEX0JZVEVTVFJJTkcgPSAweGUwLAo+ICsJT1BBTF9EVEFfVE9LRU5JRF9T
SU5UID0gMHhlMSwKPiArCU9QQUxfRFRBX1RPS0VOSURfVUlOVCA9IDB4ZTIsCj4gKwlPUEFMX0RU
QV9UT0tFTklEX1RPS0VOID0gMHhlMywgLyogYWN0dWFsIHRva2VuIGlzIHJldHVybmVkICovCj4g
KwlPUEFMX0RUQV9UT0tFTklEX0lOVkFMSUQgPSAwWDAKPiArfTsKPiArCj4gK2VudW0gT1BBTF9U
T0tFTiB7Cj4gKwkvKiBCb29sZWFuICovCj4gKwlPUEFMX1RSVUUgPSAweDAxLAo+ICsJT1BBTF9G
QUxTRSA9IDB4MDAsCj4gKwlPUEFMX0JPT0xFQU5fRVhQUiA9IDB4MDMsCj4gKwkvKiBjZWxsYmxv
Y2tzICovCj4gKwlPUEFMX1RBQkxFID0gMHgwMCwKPiArCU9QQUxfU1RBUlRST1cgPSAweDAxLAo+
ICsJT1BBTF9FTkRST1cgPSAweDAyLAo+ICsJT1BBTF9TVEFSVENPTFVNTiA9IDB4MDMsCj4gKwlP
UEFMX0VORENPTFVNTiA9IDB4MDQsCj4gKwlPUEFMX1ZBTFVFUyA9IDB4MDEsCj4gKwkvKiBhdXRo
b3JpdHkgdGFibGUgKi8KPiArCU9QQUxfUElOID0gMHgwMywKPiArCS8qIGxvY2tpbmcgdG9rZW5z
ICovCj4gKwlPUEFMX1JBTkdFU1RBUlQgPSAweDAzLAo+ICsJT1BBTF9SQU5HRUxFTkdUSCA9IDB4
MDQsCj4gKwlPUEFMX1JFQURMT0NLRU5BQkxFRCA9IDB4MDUsCj4gKwlPUEFMX1dSSVRFTE9DS0VO
QUJMRUQgPSAweDA2LAo+ICsJT1BBTF9SRUFETE9DS0VEID0gMHgwNywKPiArCU9QQUxfV1JJVEVM
T0NLRUQgPSAweDA4LAo+ICsJT1BBTF9BQ1RJVkVLRVkgPSAweDBBLAo+ICsJLyogbG9ja2luZyBp
bmZvIHRhYmxlICovCj4gKwlPUEFMX01BWFJBTkdFUyA9IDB4MDQsCj4gKwkgLyogbWJyIGNvbnRy
b2wgKi8KPiArCU9QQUxfTUJSRU5BQkxFID0gMHgwMSwKPiArCU9QQUxfTUJSRE9ORSA9IDB4MDIs
Cj4gKwkvKiBwcm9wZXJ0aWVzICovCj4gKwlPUEFMX0hPU1RQUk9QRVJUSUVTID0gMHgwMCwKPiAr
CS8qIGF0b21zICovCj4gKwlPUEFMX1NUQVJUTElTVCA9IDB4ZjAsCj4gKwlPUEFMX0VORExJU1Qg
PSAweGYxLAo+ICsJT1BBTF9TVEFSVE5BTUUgPSAweGYyLAo+ICsJT1BBTF9FTkROQU1FID0gMHhm
MywKPiArCU9QQUxfQ0FMTCA9IDB4ZjgsCj4gKwlPUEFMX0VORE9GREFUQSA9IDB4ZjksCj4gKwlP
UEFMX0VORE9GU0VTU0lPTiA9IDB4ZmEsCj4gKwlPUEFMX1NUQVJUVFJBTlNBQ1RPTiA9IDB4ZmIs
Cj4gKwlPUEFMX0VORFRSQU5TQUNUT04gPSAweGZDLAo+ICsJT1BBTF9FTVBUWUFUT00gPSAweGZm
LAo+ICsJT1BBTF9XSEVSRSA9IDB4MDAsCj4gK307Cj4gKwo+ICsvKiBVc2VmdWwgdGlueSBhdG9t
cy4KPiArICogVXNlZnVsIGZvciB0YWJsZSBjb2x1bW5zIGV0Ywo+ICsgKi8KPiArZW51bSBPUEFM
X1RJTllfQVRPTSB7Cj4gKwlPUEFMX1RJTllfVUlOVF8wMCA9IDB4MDAsCj4gKwlPUEFMX1RJTllf
VUlOVF8wMSA9IDB4MDEsCj4gKwlPUEFMX1RJTllfVUlOVF8wMiA9IDB4MDIsCj4gKwlPUEFMX1RJ
TllfVUlOVF8wMyA9IDB4MDMsCj4gKwlPUEFMX1RJTllfVUlOVF8wNCA9IDB4MDQsCj4gKwlPUEFM
X1RJTllfVUlOVF8wNSA9IDB4MDUsCj4gKwlPUEFMX1RJTllfVUlOVF8wNiA9IDB4MDYsCj4gKwlP
UEFMX1RJTllfVUlOVF8wNyA9IDB4MDcsCj4gKwlPUEFMX1RJTllfVUlOVF8wOCA9IDB4MDgsCj4g
KwlPUEFMX1RJTllfVUlOVF8wOSA9IDB4MDksCj4gKwlPUEFMX1RJTllfVUlOVF8xMCA9IDB4MGEs
Cj4gKwlPUEFMX1RJTllfVUlOVF8xMSA9IDB4MGIsCj4gKwlPUEFMX1RJTllfVUlOVF8xMiA9IDB4
MGMsCj4gKwlPUEFMX1RJTllfVUlOVF8xMyA9IDB4MGQsCj4gKwlPUEFMX1RJTllfVUlOVF8xNCA9
IDB4MGUsCj4gKwlPUEFMX1RJTllfVUlOVF8xNSA9IDB4MGYsCj4gK307Cj4gKwo+ICtlbnVtIE9Q
QUxfQVRPTV9XSURUSCB7Cj4gKwlPUEFMX1dJRFRIX1RJTlksCj4gKwlPUEFMX1dJRFRIX1NIT1JU
LAo+ICsJT1BBTF9XSURUSF9NRURJVU0sCj4gKwlPUEFMX1dJRFRIX0xPTkcsCj4gKwlPUEFMX1dJ
RFRIX1RPS0VOCj4gK307Cj4gKwo+ICsvKiBMb2NraW5nIHN0YXRlIGZvciBhIGxvY2tpbmcgcmFu
Z2UgKi8KPiArZW51bSBPUEFMX0xPQ0tJTkdTVEFURSB7Cj4gKwlPUEFMX0xPQ0tJTkdfUkVBRFdS
SVRFID0gMHgwMSwKPiArCU9QQUxfTE9DS0lOR19SRUFET05MWSA9IDB4MDIsCj4gKwlPUEFMX0xP
Q0tJTkdfTE9DS0VEID0gMHgwMywKPiArfTsKPiArCj4gKy8qCj4gKyAqIFN0cnVjdHVyZXMgdG8g
YnVpbGQgYW5kIGRlY29kZSB0aGUgT3BhbCBTU0MgbWVzc2FnZXMKPiArICogZmllbGRzIHRoYXQg
YXJlIE5PVCByZWFsbHkgbnVtZXJpYyBhcmUgZGVmaW5lZCBhcyB1OFtdIHRvCj4gKyAqIGhlbHAg
cmVkdWNlIHRoZSBlbmRpYW5uZXNzIGlzc3Vlcwo+ICsgKi8KPiArCj4gKy8qIENvbW0gUGFja2V0
IChoZWFkZXIpIGZvciB0cmFuc21pc3Npb25zLiAqLwo+ICtzdHJ1Y3Qgb3BhbF9jb21wYWNrZXQg
ewo+ICsJdTMyIHJlc2VydmVkMDsKPiArCXU4IGV4dGVuZGVkQ29tSURbNF07Cj4gKwl1MzIgb3V0
c3RhbmRpbmdEYXRhOwo+ICsJdTMyIG1pblRyYW5zZmVyOwo+ICsJdTMyIGxlbmd0aDsKPiArfTsK
PiArCj4gKy8qIFBhY2tldCBzdHJ1Y3R1cmUuICovCj4gK3N0cnVjdCBvcGFsX3BhY2tldCB7Cj4g
Kwl1MzIgVFNOOwo+ICsJdTMyIEhTTjsKPiArCXUzMiBzZXFfbnVtYmVyOwo+ICsJdTE2IHJlc2Vy
dmVkMDsKPiArCXUxNiBhY2tfdHlwZTsKPiArCXUzMiBhY2tub3dsZWRnbWVudDsKPiArCXUzMiBs
ZW5ndGg7Cj4gK307Cj4gKwo+ICsvKiBEYXRhIHN1YiBwYWNrZXQgaGVhZGVyICovCj4gK3N0cnVj
dCBvcGFsX2RhdGFfc3VicGFja2V0IHsKPiArCXU4IHJlc2VydmVkMFs2XTsKPiArCXUxNiBraW5k
Owo+ICsJdTMyIGxlbmd0aDsKPiArfTsKPiArCj4gKy8qIGhlYWRlciBvZiBhIHJlc3BvbnNlICov
Cj4gK3N0cnVjdCBvcGFsX2hlYWRlciB7Cj4gKwlzdHJ1Y3Qgb3BhbF9jb21wYWNrZXQgY3A7Cj4g
KwlzdHJ1Y3Qgb3BhbF9wYWNrZXQgcGt0Owo+ICsJc3RydWN0IG9wYWxfZGF0YV9zdWJwYWNrZXQg
c3VicGt0Owo+ICt9Owo+ICsKPiArI2RlZmluZSBGQ19UUEVSICAgICAgIDB4MDAwMQo+ICsjZGVm
aW5lIEZDX0xPQ0tJTkcgICAgMHgwMDAyCj4gKyNkZWZpbmUgRkNfR0VPTUVUUlkgICAweDAwMDMK
PiArI2RlZmluZSBGQ19FTlRFUlBSSVNFIDB4MDEwMAo+ICsjZGVmaW5lIEZDX0RBVEFTVE9SRSAg
MHgwMjAyCj4gKyNkZWZpbmUgRkNfU0lOR0xFVVNFUiAweDAyMDEKPiArI2RlZmluZSBGQ19PUEFM
VjEwMCAgIDB4MDIwMAo+ICsjZGVmaW5lIEZDX09QQUxWMjAwICAgMHgwMjAzCj4gKwo+ICsvKgo+
ICsgKiBUaGUgRGlzY292ZXJ5IDAgSGVhZGVyLiBBcyBkZWZpbmVkIGluCj4gKyAqIE9wYWwgU1ND
IERvY3VtZW50YXRpb24KPiArICovCj4gK3N0cnVjdCBkMF9oZWFkZXIgewo+ICsJdTMyIGxlbmd0
aDsgLyogdGhlIGxlbmd0aCBvZiB0aGUgaGVhZGVyIDQ4IGluIDIuMDAuMTAwICovCj4gKwl1MzIg
cmV2aXNpb247IC8qKjwgcmV2aXNpb24gb2YgdGhlIGhlYWRlciAxIGluIDIuMDAuMTAwICovCj4g
Kwl1MzIgcmVzZXJ2ZWQwMTsKPiArCXUzMiByZXNlcnZlZDAyOwo+ICsJLyoKPiArCSAqIHRoZSBy
ZW1haW5kZXIgb2YgdGhlIHN0cnVjdHVyZSBpcyB2ZW5kb3Igc3BlY2lmaWMgYW5kIHdpbGwgbm90
IGJlCj4gKwkgKiBhZGRyZXNzZWQgbm93Cj4gKwkgKi8KPiArCXU4IGlnbm9yZWRbMzJdOwo+ICt9
Owo+ICsKPiArLyoKPiArICogVFBlciBGZWF0dXJlIERlc2NyaXB0b3IuIENvbnRhaW5zIGZsYWdz
IGluZGljYXRpbmcgc3VwcG9ydCBmb3IgdGhlCj4gKyAqIFRQZXIgZmVhdHVyZXMgZGVzY3JpYmVk
IGluIHRoZSBPUEFMIHNwZWNpZmljYXRpb24uIFRoZSBuYW1lcyBtYXRjaCB0aGUKPiArICogT1BB
TCB0ZXJtaW5vbG9neQo+ICsgKgo+ICsgKiBjb2RlID09IDB4MDAxIGluIDIuMDAuMTAwCj4gKyAq
Lwo+ICtzdHJ1Y3QgZDBfdHBlcl9mZWF0dXJlcyB7Cj4gKwkvKgo+ICsJICogc3VwcG9ydGVkX2Zl
YXR1cmVzIGJpdHM6Cj4gKwkgKiBiaXQgNzogcmVzZXJ2ZWQKPiArCSAqIGJpdCA2OiBjb20gSUQg
bWFuYWdlbWVudAo+ICsJICogYml0IDU6IHJlc2VydmVkCj4gKwkgKiBiaXQgNDogc3RyZWFtaW5n
IHN1cHBvcnQKPiArCSAqIGJpdCAzOiBidWZmZXIgbWFuYWdlbWVudAo+ICsJICogYml0IDI6IEFD
Sy9OQUNLCj4gKwkgKiBiaXQgMTogYXN5bmMKPiArCSAqIGJpdCAwOiBzeW5jCj4gKwkgKi8KPiAr
CXU4IHN1cHBvcnRlZF9mZWF0dXJlczsKPiArCS8qCj4gKwkgKiBieXRlcyA1IHRocm91Z2ggMTUg
YXJlIHJlc2VydmVkLCBidXQgd2UgcmVwcmVzZW50IHRoZSBmaXJzdCAzIGFzCj4gKwkgKiB1OCB0
byBrZWVwIHRoZSBvdGhlciB0d28gMzJiaXRzIGludGVnZXJzIGFsaWduZWQuCj4gKwkgKi8KPiAr
CXU4IHJlc2VydmVkMDFbM107Cj4gKwl1MzIgcmVzZXJ2ZWQwMjsKPiArCXUzMiByZXNlcnZlZDAz
Owo+ICt9Owo+ICsKPiArLyoKPiArICogTG9ja2luZyBGZWF0dXJlIERlc2NyaXB0b3IuIENvbnRh
aW5zIGZsYWdzIGluZGljYXRpbmcgc3VwcG9ydCBmb3IgdGhlCj4gKyAqIGxvY2tpbmcgZmVhdHVy
ZXMgZGVzY3JpYmVkIGluIHRoZSBPUEFMIHNwZWNpZmljYXRpb24uIFRoZSBuYW1lcyBtYXRjaCB0
aGUKPiArICogT1BBTCB0ZXJtaW5vbG9neQo+ICsgKgo+ICsgKiBjb2RlID09IDB4MDAwMiBpbiAy
LjAwLjEwMAo+ICsgKi8KPiArc3RydWN0IGQwX2xvY2tpbmdfZmVhdHVyZXMgewo+ICsJLyoKPiAr
CSAqIHN1cHBvcnRlZF9mZWF0dXJlcyBiaXRzOgo+ICsJICogYml0cyA2LTc6IHJlc2VydmVkCj4g
KwkgKiBiaXQgNTogTUJSIGRvbmUKPiArCSAqIGJpdCA0OiBNQlIgZW5hYmxlZAo+ICsJICogYml0
IDM6IG1lZGlhIGVuY3J5cHRpb24KPiArCSAqIGJpdCAyOiBsb2NrZWQKPiArCSAqIGJpdCAxOiBs
b2NraW5nIGVuYWJsZWQKPiArCSAqIGJpdCAwOiBsb2NraW5nIHN1cHBvcnRlZAo+ICsJICovCj4g
Kwl1OCBzdXBwb3J0ZWRfZmVhdHVyZXM7Cj4gKwkvKgo+ICsJICogYnl0ZXMgNSB0aHJvdWdoIDE1
IGFyZSByZXNlcnZlZCwgYnV0IHdlIHJlcHJlc2VudCB0aGUgZmlyc3QgMyBhcwo+ICsJICogdTgg
dG8ga2VlcCB0aGUgb3RoZXIgdHdvIDMyYml0cyBpbnRlZ2VycyBhbGlnbmVkLgo+ICsJICovCj4g
Kwl1OCByZXNlcnZlZDAxWzNdOwo+ICsJdTMyIHJlc2VydmVkMDI7Cj4gKwl1MzIgcmVzZXJ2ZWQw
MzsKPiArfTsKPiArCj4gKy8qCj4gKyAqIEdlb21ldHJ5IEZlYXR1cmUgRGVzY3JpcHRvci4gQ29u
dGFpbnMgZmxhZ3MgaW5kaWNhdGluZyBzdXBwb3J0IGZvciB0aGUKPiArICogZ2VvbWV0cnkgZmVh
dHVyZXMgZGVzY3JpYmVkIGluIHRoZSBPUEFMIHNwZWNpZmljYXRpb24uIFRoZSBuYW1lcyBtYXRj
aCB0aGUKPiArICogT1BBTCB0ZXJtaW5vbG9neQo+ICsgKgo+ICsgKiBjb2RlID09IDB4MDAwMyBp
biAyLjAwLjEwMAo+ICsgKi8KPiArc3RydWN0IGQwX2dlb21ldHJ5X2ZlYXR1cmVzIHsKPiArCS8q
Cj4gKwkgKiBza2lwIDMyIGJpdHMgZnJvbSBoZWFkZXIsIG5lZWRlZCB0byBhbGlnbiB0aGUgc3Ry
dWN0IHRvIDY0IGJpdHMuCj4gKwkgKi8KPiArCXU4IGhlYWRlcls0XTsKPiArCS8qCj4gKwkgKiBy
ZXNlcnZlZDAxOgo+ICsJICogYml0cyAxLTY6IHJlc2VydmVkCj4gKwkgKiBiaXQgMDogYWxpZ24K
PiArCSAqLwo+ICsJdTggcmVzZXJ2ZWQwMTsKPiArCXU4IHJlc2VydmVkMDJbN107Cj4gKwl1MzIg
bG9naWNhbF9ibG9ja19zaXplOwo+ICsJdTY0IGFsaWdubWVudF9ncmFudWxhcml0eTsKPiArCXU2
NCBsb3dlc3RfYWxpZ25lZF9sYmE7Cj4gK307Cj4gKwo+ICsvKgo+ICsgKiBFbnRlcnByaXNlIFNT
QyBGZWF0dXJlCj4gKyAqCj4gKyAqIGNvZGUgPT0gMHgwMTAwCj4gKyAqLwo+ICtzdHJ1Y3QgZDBf
ZW50ZXJwcmlzZV9zc2Mgewo+ICsJdTE2IGJhc2VDb21JRDsKPiArCXUxNiBudW1Db21JRHM7Cj4g
KwkvKiByYW5nZV9jcm9zc2luZzoKPiArCSAqIGJpdHMgMS02OiByZXNlcnZlZAo+ICsJICogYml0
IDA6IHJhbmdlIGNyb3NzaW5nCj4gKwkgKi8KPiArCXU4IHJhbmdlX2Nyb3NzaW5nOwo+ICsJdTgg
cmVzZXJ2ZWQwMTsKPiArCXUxNiByZXNlcnZlZDAyOwo+ICsJdTMyIHJlc2VydmVkMDM7Cj4gKwl1
MzIgcmVzZXJ2ZWQwNDsKPiArfTsKPiArCj4gKy8qCj4gKyAqIE9wYWwgVjEgZmVhdHVyZQo+ICsg
Kgo+ICsgKiBjb2RlID09IDB4MDIwMAo+ICsgKi8KPiArc3RydWN0IGQwX29wYWxfdjEwMCB7Cj4g
Kwl1MTYgYmFzZUNvbUlEOwo+ICsJdTE2IG51bUNvbUlEczsKPiArfTsKPiArCj4gKy8qCj4gKyAq
IFNpbmdsZSBVc2VyIE1vZGUgZmVhdHVyZQo+ICsgKgo+ICsgKiBjb2RlID09IDB4MDIwMQo+ICsg
Ki8KPiArc3RydWN0IGQwX3NpbmdsZV91c2VyX21vZGUgewo+ICsJdTMyIG51bV9sb2NraW5nX29i
amVjdHM7Cj4gKwkvKiByZXNlcnZlZDAxOgo+ICsJICogYml0IDA6IGFueQo+ICsJICogYml0IDE6
IGFsbAo+ICsJICogYml0IDI6IHBvbGljeQo+ICsJICogYml0cyAzLTc6IHJlc2VydmVkCj4gKwkg
Ki8KPiArCXU4IHJlc2VydmVkMDE7Cj4gKwl1OCByZXNlcnZlZDAyOwo+ICsJdTE2IHJlc2VydmVk
MDM7Cj4gKwl1MzIgcmVzZXJ2ZWQwNDsKPiArfTsKPiArCj4gKy8qCj4gKyAqIEFkZGl0b25hbCBE
YXRhc3RvcmVzIGZlYXR1cmUKPiArICoKPiArICogY29kZSA9PSAweDAyMDIKPiArICovCj4gK3N0
cnVjdCBkMF9kYXRhc3RvcmVfdGFibGUgewo+ICsJdTE2IHJlc2VydmVkMDE7Cj4gKwl1MTYgbWF4
X3RhYmxlczsKPiArCXUzMiBtYXhfc2l6ZV90YWJsZXM7Cj4gKwl1MzIgdGFibGVfc2l6ZV9hbGln
bm1lbnQ7Cj4gK307Cj4gKwo+ICsvKgo+ICsgKiBPUEFMIDIuMCBmZWF0dXJlCj4gKyAqCj4gKyAq
IGNvZGUgPT0gMHgwMjAzCj4gKyAqLwo+ICtzdHJ1Y3QgZDBfb3BhbF92MjAwIHsKPiArCXUxNiBi
YXNlQ29tSUQ7Cj4gKwl1MTYgbnVtQ29tSURzOwo+ICsJLyogcmFuZ2VfY3Jvc3Npbmc6Cj4gKwkg
KiBiaXRzIDEtNjogcmVzZXJ2ZWQKPiArCSAqIGJpdCAwOiByYW5nZSBjcm9zc2luZwo+ICsJICov
Cj4gKwl1OCByYW5nZV9jcm9zc2luZzsKPiArCS8qIG51bV9sb2NraW5nX2FkbWluX2F1dGg6Cj4g
KwkgKiBub3QgYWxpZ25lZCB0byAxNiBiaXRzLCBzbyB1c2UgdHdvIHU4Lgo+ICsJICogc3RvcmVk
IGluIGJpZyBlbmRpYW46Cj4gKwkgKiAwOiBNU0IKPiArCSAqIDE6IExTQgo+ICsJICovCj4gKwl1
OCBudW1fbG9ja2luZ19hZG1pbl9hdXRoWzJdOwo+ICsJLyogbnVtX2xvY2tpbmdfdXNlcl9hdXRo
Ogo+ICsJICogbm90IGFsaWduZWQgdG8gMTYgYml0cywgc28gdXNlIHR3byB1OC4KPiArCSAqIHN0
b3JlZCBpbiBiaWcgZW5kaWFuOgo+ICsJICogMDogTVNCCj4gKwkgKiAxOiBMU0IKPiArCSAqLwo+
ICsJdTggbnVtX2xvY2tpbmdfdXNlcl9hdXRoWzJdOwo+ICsJdTggaW5pdGlhbFBJTjsKPiArCXU4
IHJldmVydGVkUElOOwo+ICsJdTggcmVzZXJ2ZWQwMTsKPiArCXUzMiByZXNlcnZlZDAyOwo+ICt9
Owo+ICsKPiArLyogVW5pb24gb2YgZmVhdHVyZXMgdXNlZCB0byBwYXJzZSB0aGUgZGlzY292ZXJ5
IDAgcmVzcG9uc2UgKi8KPiArc3RydWN0IGQwX2ZlYXR1cmVzIHsKPiArCXUxNiBjb2RlOwo+ICsJ
LyoKPiArCSAqIHJfdmVyc2lvbiBiaXRzOgo+ICsJICogYml0cyA0LTc6IHZlcnNpb24KPiArCSAq
IGJpdHMgMC0zOiByZXNlcnZlZAo+ICsJICovCj4gKwl1OCByX3ZlcnNpb247Cj4gKwl1OCBsZW5n
dGg7Cj4gKwl1OCBmZWF0dXJlc1tdOwo+ICt9Owo+ICsKPiArc3RydWN0IGtleSAqcmVxdWVzdF91
c2VyX2tleShjb25zdCBjaGFyICptYXN0ZXJfZGVzYywgY29uc3QgdTggKiptYXN0ZXJfa2V5LAo+
ICsJCQkgICAgIHNpemVfdCAqbWFzdGVyX2tleWxlbik7Cj4gKwo+ICsjZW5kaWYgLyogX05WTUVf
T1BBTF9JTlRFUk5BTF9IICovCj4gZGlmZiAtLWdpdCBhL2xpYi9zZWQtb3BhbF9rZXkuYyBiL2xp
Yi9zZWQtb3BhbF9rZXkuYwo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMC4u
MGI0ZGUwMQo+IC0tLSAvZGV2L251bGwKPiArKysgYi9saWIvc2VkLW9wYWxfa2V5LmMKPiBAQCAt
MCwwICsxLDQ2IEBACj4gKy8qCj4gKyAqIENvcHlyaWdodCDCqSAyMDE2IEludGVsIENvcnBvcmF0
aW9uCj4gKyAqCj4gKyAqIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hh
cmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhCj4gKyAqIGNvcHkgb2YgdGhpcyBzb2Z0d2Fy
ZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksCj4g
KyAqIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGlu
ZyB3aXRob3V0IGxpbWl0YXRpb24KPiArICogdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlm
eSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsCj4gKyAqIGFuZC9vciBz
ZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9t
IHRoZQo+ICsgKiBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhl
IGZvbGxvd2luZyBjb25kaXRpb25zOgo+ICsgKgo+ICsgKiBUaGUgYWJvdmUgY29weXJpZ2h0IG5v
dGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSAoaW5jbHVkaW5nIHRoZSBuZXh0Cj4gKyAq
IHBhcmFncmFwaCkgc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlh
bCBwb3J0aW9ucyBvZiB0aGUKPiArICogU29mdHdhcmUuCj4gKyAqCj4gKyAqIFRIRSBTT0ZUV0FS
RSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBS
RVNTIE9SCj4gKyAqIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdB
UlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLAo+ICsgKiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VM
QVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiAgSU4gTk8gRVZFTlQgU0hBTEwKPiArICog
VEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0s
IERBTUFHRVMgT1IgT1RIRVIKPiArICogTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBP
RiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcKPiArICogRlJPTSwgT1VUIE9G
IE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBE
RUFMSU5HUwo+ICsgKiBJTiBUSEUgU09GVFdBUkUuCj4gKyAqCj4gKyAqIEF1dGhvcjoKPiArICog
ICAgUmFmYWVsIEFudG9nbm9sbGkgPHJhZmFlbC5hbnRvZ25vbGxpQGludGVsLmNvbT4KPiArICov
Cj4gKwo+ICsjaW5jbHVkZSA8bGludXgva2V5Lmg+Cj4gKyNpbmNsdWRlICJzZWQtb3BhbF9pbnRl
cm5hbC5oIgo+ICsKPiArc3RydWN0IGtleSAqcmVxdWVzdF91c2VyX2tleShjb25zdCBjaGFyICpt
YXN0ZXJfZGVzYywgY29uc3QgdTggKiptYXN0ZXJfa2V5LAo+ICsJCQkgICAgIHNpemVfdCAqbWFz
dGVyX2tleWxlbikKPiArewo+ICsJY29uc3Qgc3RydWN0IHVzZXJfa2V5X3BheWxvYWQgKnVwYXls
b2FkOwo+ICsJc3RydWN0IGtleSAqdWtleTsKPiArCj4gKwl1a2V5ID0gcmVxdWVzdF9rZXkoJmtl
eV90eXBlX3VzZXIsIG1hc3Rlcl9kZXNjLCBOVUxMKTsKPiArCWlmIChJU19FUlIodWtleSkpCj4g
KwkJZ290byBlcnJvcjsKPiArCj4gKwlkb3duX3JlYWQoJnVrZXktPnNlbSk7Cj4gKwl1cGF5bG9h
ZCA9IHVzZXJfa2V5X3BheWxvYWQodWtleSk7Cj4gKwkqbWFzdGVyX2tleSA9IHVwYXlsb2FkLT5k
YXRhOwo+ICsJKm1hc3Rlcl9rZXlsZW4gPSB1cGF5bG9hZC0+ZGF0YWxlbjsKPiArZXJyb3I6Cj4g
KwlyZXR1cm4gdWtleTsKPiArfQo+IGRpZmYgLS1naXQgYS9saWIvc2VkLmMgYi9saWIvc2VkLmMK
PiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAuLjA2Y2FjZDkKPiAtLS0gL2Rl
di9udWxsCj4gKysrIGIvbGliL3NlZC5jCj4gQEAgLTAsMCArMSwzMDMgQEAKPiArI2luY2x1ZGUg
PGxpbnV4L2Jsa2Rldi5oPgo+ICsjaW5jbHVkZSA8bGludXgvc2VkLmg+Cj4gKyNpbmNsdWRlIDxs
aW51eC9zZWQtb3BhbC5oPgo+ICsKPiArI2lmbmRlZiBDT05GSUdfU0VEX09QQUwKPiArc3RhdGlj
IGludCBzZWRfb3BhbF9zYXZlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRf
a2V5ICpzZWQpCj4gKwl7IHJldHVybiAtRU9QTk9UU1VQUDsgfQo+ICtzdGF0aWMgaW50IHNlZF9v
cGFsX2xvY2tfdW5sb2NrKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5
ICprZXkpCj4gKwl7IHJldHVybiAtRU9QTk9UU1VQUDsgfQo+ICtzdGF0aWMgaW50IHNlZF9vcGFs
X3Rha2Vfb3duZXJzaGlwKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5
ICprZXkpCj4gKwl7IHJldHVybiAtRU9QTk9UU1VQUDsgfQo+ICtzdGF0aWMgaW50IHNlZF9vcGFs
X2FjdGl2YXRlX2xzcChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAq
a2V5KQo+ICsJeyByZXR1cm4gLUVPUE5PVFNVUFA7IH0KPiArc3RhdGljIGludCBzZWRfb3BhbF9z
ZXRfcHcoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKPiAr
CXsgcmV0dXJuIC1FT1BOT1RTVVBQOyB9Cj4gK3N0YXRpYyBpbnQgc2VkX29wYWxfYWN0aXZhdGVf
dXNlcihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICsJ
eyByZXR1cm4gLUVPUE5PVFNVUFA7IH0KPiArc3RhdGljIGludCBzZWRfb3BhbF9yZXZlcnR0cGVy
KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4gKwl7IHJl
dHVybiAtRU9QTk9UU1VQUDsgfQo+ICtzdGF0aWMgaW50IHNlZF9vcGFsX3NldHVwX2xvY2tpbmdf
cmFuZ2Uoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKPiAr
CXsgcmV0dXJuIC1FT1BOT1RTVVBQOyB9Cj4gK3N0YXRpYyBpbnQgc2VkX29wYWxfYWRkdXNlcl90
b19scihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICsJ
eyByZXR1cm4gLUVPUE5PVFNVUFA7IH0KPiArc3RhdGljIGludCBzZWRfb3BhbF9kb19tYnIoc3Ry
dWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKPiArCXsgcmV0dXJu
IC1FT1BOT1RTVVBQOyB9Cj4gK3N0YXRpYyBpbnQgc2VkX29wYWxfZXJhc2VfbHIoc3RydWN0IGJs
b2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKPiArCXsgcmV0dXJuIC1FT1BO
T1RTVVBQOyB9Cj4gKwo+ICsjZWxzZQo+ICsKPiArc3RhdGljIGludCBzZWRfb3BhbF9zYXZlKHN0
cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4gK3sKPiArCj4g
KwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwK
PiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5P
VFNVUFA7CllvdSBtaWdodCBjb25zaWRlciBwdWxsaW5nIHRoaXMgYm9pbGVycGxhdGUgb3V0IGlu
dG8gc29tZXRoaW5nIGxpa2U6CnN0YXRpYyBpbmxpbmUgYm9vbCBiZGV2X3NlY19jYXBhYmxlKHN0
cnVjdCBibG9ja19kZXZpY2UgKmJkZXYpCnsKCXJldHVybiBiZGV2ICYmIGJkZXYtPmJkX2Rpc2sg
JiYgYmRldi0+YmRfZGlzay0+Zm9wcyAmJgoJICAgICAgIGJkZXYtPmJkX2Rpc2stPmZvcHMtPnNl
Y19vcHM7Cn0KCgo+ICsKPiArCXJldHVybiBvcGFsX3NhdmUoYmRldiwga2V5KTsKPiArfQo+ICsK
PiArc3RhdGljIGludCBzZWRfb3BhbF9sb2NrX3VubG9jayhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpi
ZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2
LT5iZF9kaXNrIHx8ICFiZGV2LT5iZF9kaXNrLT5mb3BzIHx8Cj4gKwkgICAgIWJkZXYtPmJkX2Rp
c2stPmZvcHMtPnNlY19vcHMpCj4gKwkJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICsKPiArCXJldHVy
biBvcGFsX2xvY2tfdW5sb2NrKGJkZXYsIGtleSk7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgc2Vk
X29wYWxfdGFrZV9vd25lcnNoaXAoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwKPiArCQkJCSAg
IHN0cnVjdCBzZWRfa2V5ICprZXkpCj4gK3sKPiArCj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJk
X2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+
Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJcmV0dXJuIG9w
YWxfdGFrZV9vd25lcnNoaXAoYmRldiwga2V5KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBzZWRf
b3BhbF9hY3RpdmF0ZV9sc3Aoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwKPiArCQkJCSBzdHJ1
Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNr
IHx8ICFiZGV2LT5iZF9kaXNrLT5mb3BzIHx8Cj4gKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMt
PnNlY19vcHMpCj4gKwkJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICsKPiArCXJldHVybiBvcGFsX2Fj
dGl2YXRlX2xzcChiZGV2LCBrZXkpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNlZF9vcGFsX3Nl
dF9wdyhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LAo+ICsJCQkgICBzdHJ1Y3Qgc2VkX2tleSAq
a2V5KQo+ICt7Cj4gKwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrIHx8ICFiZGV2LT5i
ZF9kaXNrLT5mb3BzIHx8Cj4gKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19vcHMpCj4g
KwkJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICsKPiArCXJldHVybiBvcGFsX3NldF9uZXdfcHcoYmRl
diwga2V5KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBzZWRfb3BhbF9hY3RpdmF0ZV91c2VyKHN0
cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCQkgIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4g
K3sKPiArCj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2st
PmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1
cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJcmV0dXJuIG9wYWxfYWN0aXZhdGVfdXNlcihiZGV2LCBr
ZXkpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNlZF9vcGFsX3JldmVydHRwZXIoc3RydWN0IGJs
b2NrX2RldmljZSAqYmRldiwKPiArCQkJICAgICAgIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4gK3sK
PiArCj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZv
cHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4g
LUVPUE5PVFNVUFA7Cj4gKwo+ICsJcmV0dXJuIG9wYWxfcmV2ZXJ0dHBlcihiZGV2LCBrZXkpOwo+
ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNlZF9vcGFsX3NldHVwX2xyKHN0cnVjdCBibG9ja19kZXZp
Y2UgKmJkZXYsCj4gKwkJCSAgICAgc3RydWN0IHNlZF9rZXkgKmtleSkKPiArewo+ICsKPiArCWlm
ICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRfZGlzay0+Zm9wcyB8fAo+ICsJ
ICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQo+ICsJCXJldHVybiAtRU9QTk9UU1VQ
UDsKPiArCj4gKwlyZXR1cm4gb3BhbF9zZXR1cF9sb2NraW5nX3JhbmdlKGJkZXYsIGtleSk7Cj4g
K30KPiArCj4gK3N0YXRpYyBpbnQgc2VkX29wYWxfYWRkdXNlcl90b19scihzdHJ1Y3QgYmxvY2tf
ZGV2aWNlICpiZGV2LAo+ICsJCQkgICAgIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4gK3sKPiArCj4g
KwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwK
PiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5P
VFNVUFA7Cj4gKwo+ICsJcmV0dXJuIG9wYWxfYWRkX3VzZXJfdG9fbHIoYmRldiwga2V5KTsKPiAr
fQo+ICsKPiArc3RhdGljIGludCBzZWRfb3BhbF9kb19tYnIoc3RydWN0IGJsb2NrX2RldmljZSAq
YmRldiwKPiArCQkJICAgc3RydWN0IHNlZF9rZXkgKmtleSkKPiArewo+ICsKPiArCWlmICghYmRl
diB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRfZGlzay0+Zm9wcyB8fAo+ICsJICAgICFi
ZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQo+ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiAr
Cj4gKwlyZXR1cm4gb3BhbF9lbmFibGVfZGlzYWJsZV9zaGFkb3dfbWJyKGJkZXYsIGtleSk7Cj4g
K30KPiArCj4gK3N0YXRpYyBpbnQgc2VkX29wYWxfZXJhc2VfbHIoc3RydWN0IGJsb2NrX2Rldmlj
ZSAqYmRldiwKPiArCQkJICAgICBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwo+ICsJaWYg
KCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrIHx8ICFiZGV2LT5iZF9kaXNrLT5mb3BzIHx8Cj4gKwkg
ICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19vcHMpCj4gKwkJcmV0dXJuIC1FT1BOT1RTVVBQ
Owo+ICsKPiArCXJldHVybiBvcGFsX2VyYXNlX2xvY2tpbmdfcmFuZ2UoYmRldiwga2V5KTsKPiAr
fQo+ICsjZW5kaWYKPiArCj4gK2ludCBzZWRfc2F2ZShzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2
LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rp
c2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9w
cy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJc3dpdGNoIChrZXkt
PnNlZF90eXBlKSB7Cj4gKwljYXNlIE9QQUxfTE9DS19VTkxPQ0s6Cj4gKwkJcmV0dXJuIHNlZF9v
cGFsX3NhdmUoYmRldiwga2V5KTsKPiArCX0KPiArCj4gKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4g
K30KPiArCj4gK2ludCBzZWRfbG9ja191bmxvY2soc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwg
c3RydWN0IHNlZF9rZXkgKmtleSkKPiArewo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNr
IHx8ICFiZGV2LT5iZF9kaXNrLT5mb3BzIHx8Cj4gKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMt
PnNlY19vcHMpCj4gKwkJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICsKPiArCXN3aXRjaCAoa2V5LT5z
ZWRfdHlwZSkgewo+ICsJY2FzZSBPUEFMX0xPQ0tfVU5MT0NLOgo+ICsJCXJldHVybiBzZWRfb3Bh
bF9sb2NrX3VubG9jayhiZGV2LCBrZXkpOwo+ICsJfQo+ICsKPiArCXJldHVybiAtRU9QTk9UU1VQ
UDsKPiArfQo+ICsKPiAraW50IHNlZF90YWtlX293bmVyc2hpcChzdHJ1Y3QgYmxvY2tfZGV2aWNl
ICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYt
PmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlz
ay0+Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJc3dpdGNo
IChrZXktPnNlZF90eXBlKSB7Cj4gKwljYXNlIE9QQUw6Cj4gKwkJcmV0dXJuIHNlZF9vcGFsX3Rh
a2Vfb3duZXJzaGlwKGJkZXYsIGtleSk7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIC1FT1BOT1RTVVBQ
Owo+ICt9Cj4gKwo+ICtpbnQgc2VkX2FjdGl2YXRlX2xzcChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpi
ZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJk
X2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+
Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJc3dpdGNoIChr
ZXktPnNlZF90eXBlKSB7Cj4gKwljYXNlIE9QQUw6Cj4gKwkJcmV0dXJuIHNlZF9vcGFsX2FjdGl2
YXRlX2xzcChiZGV2LCBrZXkpOwo+ICsJfQo+ICsKPiArCXJldHVybiAtRU9QTk9UU1VQUDsKPiAr
fQo+ICsKPiAraW50IHNlZF9zZXRfcHcoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0
IHNlZF9rZXkgKmtleSkKPiArewo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrIHx8ICFi
ZGV2LT5iZF9kaXNrLT5mb3BzIHx8Cj4gKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19v
cHMpCj4gKwkJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICsKPiArCXN3aXRjaCAoa2V5LT5zZWRfdHlw
ZSkgewo+ICsJY2FzZSBPUEFMX1BXOgo+ICsJCXJldHVybiBzZWRfb3BhbF9zZXRfcHcoYmRldiwg
a2V5KTsKPiArCX0KPiArCj4gKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gK30KPiArCj4gK2ludCBz
ZWRfYWN0aXZhdGVfdXNlcihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tl
eSAqa2V5KQo+ICt7Cj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJk
X2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKPiAr
CQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJc3dpdGNoIChrZXktPnNlZF90eXBlKSB7Cj4g
KwljYXNlIE9QQUxfQUNUX1VTUjoKPiArCQlyZXR1cm4gc2VkX29wYWxfYWN0aXZhdGVfdXNlcihi
ZGV2LCBrZXkpOwo+ICsJfQo+ICsKPiArCXJldHVybiAtRU9QTk9UU1VQUDsKPiArfQo+ICsKPiAr
aW50IHNlZF9yZXZlcnR0cGVyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRf
a2V5ICprZXkpCj4gK3sKPiArCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+
YmRfZGlzay0+Zm9wcyB8fAo+ICsJICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQo+
ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiArCj4gKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsK
PiArCWNhc2UgT1BBTDoKPiArCQlyZXR1cm4gc2VkX29wYWxfcmV2ZXJ0dHBlcihiZGV2LCBrZXkp
Owo+ICsJfQo+ICsKPiArCXJldHVybiAtRU9QTk9UU1VQUDsKPiArfQo+ICsKPiAraW50IHNlZF9z
ZXR1cF9sb2NraW5nX3JhbmdlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRf
a2V5ICprZXkpCj4gK3sKPiArCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+
YmRfZGlzay0+Zm9wcyB8fAo+ICsJICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQo+
ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiArCj4gKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsK
PiArCWNhc2UgT1BBTF9MUl9TRVRVUDoKPiArCQlyZXR1cm4gc2VkX29wYWxfc2V0dXBfbHIoYmRl
diwga2V5KTsKPiArCX0KPiArCj4gKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gK30KPiArCj4gK2lu
dCBzZWRfYWRkdXNlcl90b19scihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2Vk
X2tleSAqa2V5KQo+ICt7Cj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYt
PmJkX2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykK
PiArCQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJc3dpdGNoIChrZXktPnNlZF90eXBlKSB7
Cj4gKwljYXNlIE9QQUxfTE9DS19VTkxPQ0s6Cj4gKwkJcmV0dXJuIHNlZF9vcGFsX2FkZHVzZXJf
dG9fbHIoYmRldiwga2V5KTsKPiArCX0KPiArCj4gKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gK30K
PiArCj4gK2ludCBzZWRfZG9fbWJyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBz
ZWRfa2V5ICprZXkpCj4gK3sKPiArCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRl
di0+YmRfZGlzay0+Zm9wcyB8fAo+ICsJICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3Bz
KQo+ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiArCj4gKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUp
IHsKPiArCWNhc2UgT1BBTF9NQlJfREFUQToKPiArCQlyZXR1cm4gc2VkX29wYWxfZG9fbWJyKGJk
ZXYsIGtleSk7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICt9Cj4gKwo+ICtp
bnQgc2VkX2VyYXNlX2xyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5
ICprZXkpCj4gK3sKPiArCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRf
ZGlzay0+Zm9wcyB8fAo+ICsJICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQo+ICsJ
CXJldHVybiAtRU9QTk9UU1VQUDsKPiArCj4gKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsKPiAr
CWNhc2UgT1BBTDoKPiArCQlyZXR1cm4gc2VkX29wYWxfZXJhc2VfbHIoYmRldiwga2V5KTsKPiAr
CX0KPiArCj4gKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gK30KPiAtLSAKPiAyLjcuNAo+IAoKX19f
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KTGludXgtbnZtZSBt
YWlsaW5nIGxpc3QKTGludXgtbnZtZUBsaXN0cy5pbmZyYWRlYWQub3JnCmh0dHA6Ly9saXN0cy5p
bmZyYWRlYWQub3JnL21haWxtYW4vbGlzdGluZm8vbGludXgtbnZtZQo=

WARNING: multiple messages have this Message-ID (diff)
From: jonathan.derrick@intel.com (Jon Derrick)
Subject: [RFC PATCH 2/6] lib: Add Sed-opal library
Date: Tue, 1 Nov 2016 12:56:11 -0600	[thread overview]
Message-ID: <20161101185611.GA1999@localhost.localdomain> (raw)
In-Reply-To: <1477951099-3127-3-git-send-email-scott.bauer@intel.com>

Hi Rafael, Scott,


First off, congrats on the set! It looks good so far.

Just some small nits below since you have to respin it anyways :)

On Mon, Oct 31, 2016@03:58:15PM -0600, Scott Bauer wrote:
> This patch implements the necessary logic to bring an Opal
> enabled drive out of a factory-enabled into a working
> Opal state.
> 
> This patch set also enables logic to save a password to
> be replayed during a resume from suspend. The key can be
> saved in the driver or in the Kernel's Key managment.
> 
> Signed-off-by: Scott Bauer <scott.bauer at intel.com>
> Signed-off-by: Rafael Antognolli <Rafael.Antognolli at intel.com>
> ---
>  lib/sed-opal.c          | 3337 +++++++++++++++++++++++++++++++++++++++++++++++
>  lib/sed-opal_internal.h |  586 +++++++++
>  lib/sed-opal_key.c      |   46 +
>  lib/sed.c               |  303 +++++
>  4 files changed, 4272 insertions(+)
>  create mode 100644 lib/sed-opal.c
>  create mode 100644 lib/sed-opal_internal.h
>  create mode 100644 lib/sed-opal_key.c
>  create mode 100644 lib/sed.c
> 
> diff --git a/lib/sed-opal.c b/lib/sed-opal.c
> new file mode 100644
> index 0000000..10b3348
> --- /dev/null
> +++ b/lib/sed-opal.c
> @@ -0,0 +1,3337 @@
> +/*
> + * Copyright ? 2016 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Rafael Antognolli <rafael.antognolli at intel.com>
> + *    Scott  Bauer      <scott.bauer at intel.com>
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt
> +
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/list.h>
> +#include <linux/genhd.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +#include <uapi/linux/sed-opal.h>
> +#include <linux/sed.h>
> +#include <linux/sed-opal.h>
> +#include <linux/string.h>
> +
> +#include "sed-opal_internal.h"
> +
> +#define IO_BUFFER_LENGTH 2048
> +
> +#define MAX_TOKS 64
> +
> +struct opal_cmd {
> +	struct block_device *bdev;
> +	sec_cb *cb;
> +	void *cb_data;
> +
> +	size_t pos;
> +	u8 cmd_buf[IO_BUFFER_LENGTH * 2];
> +	u8 resp_buf[IO_BUFFER_LENGTH * 2];
> +	u8 *cmd;
> +	u8 *resp;
> +};
> +
> +/*
> + * On the parsed response, we don't store again the toks that are already
> + * stored in the response buffer. Instead, for each token, we just store a
> + * pointer to the position in the buffer where the token starts, and the size
> + * of the token in bytes.
> + */
> +struct opal_resp_tok {
> +	const u8 *pos;
> +	size_t len;
> +	enum OPAL_RESPONSE_TOKEN type;
> +	enum OPAL_ATOM_WIDTH width;
> +	union {
> +		u64 u;
> +		s64 s;
> +	} stored;
> +};
> +
> +/*
> + * From the response header it's not possible to know how many tokens there are
> + * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later
> + * if we start dealing with messages that have more than that, we can increase
> + * this number. This is done to avoid having to make two passes through the
> + * response, the first one counting how many tokens we have and the second one
> + * actually storing the positions.
> + */
> +struct parsed_resp {
> +	int num;
> +	struct opal_resp_tok toks[MAX_TOKS];
> +};
> +
> +struct opal_dev;
> +
> +typedef void (*opal_cb)(int error, struct opal_dev *dev);
> +
> +typedef int (*opal_step)(struct opal_dev *dev);
> +
> +struct opal_completion {
> +	struct completion cmd_completion;
> +	int completion_status;
> +};
> +
> +struct opal_dev {
> +	struct block_device *bdev;
> +	struct opal_completion *completion;
> +	struct opal_lock_unlock lkul;
> +	const opal_step *funcs;
> +	void **func_data;
> +	bool resume_from_suspend;
> +	struct opal_suspend_unlk *resume_data;
> +	size_t num_func_data;
> +	atomic_t in_use;
> +	sector_t start;
> +	sector_t length;
> +	u8 lr;
> +	u8 key_type;
> +	u8 key_name[OPAL_KEY_MAX];
> +	size_t key_name_len;
> +	u8 key[OPAL_KEY_MAX];
> +	size_t key_len;
> +	u16 comID;
> +	u32 HSN;
> +	u32 TSN;
> +	u64 align;
> +	u64 lowest_lba;
> +	struct list_head node;
> +	char disk_name[DISK_NAME_LEN];
> +	int state;
> +
> +	struct opal_cmd cmd;
> +	struct parsed_resp parsed;
> +
> +	size_t prev_d_len;
> +	void *prev_data;
> +
> +	sec_cb *final_cb;
> +	void *final_cb_data;
> +	opal_step error_cb;
> +	void *error_cb_data;
> +	opal_cb oper_cb;
> +};
> +
> +LIST_HEAD(opal_list);
> +DEFINE_SPINLOCK(list_spinlock);
> +
> +static void print_buffer(const u8 *ptr, u32 length)
> +{
> +#ifdef DEBUG
> +	print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
> +	pr_debug("\n");
> +#endif
> +}
> +
> +#define TPER_SYNC_SUPPORTED BIT(0)
> +
> +static bool check_tper(const void *data)
> +{
> +	const struct d0_tper_features *tper = data;
> +	u8 flags = tper->supported_features;
> +
> +	if (!(flags & TPER_SYNC_SUPPORTED)) {
> +		pr_err("TPer sync not supported. flags = %d\n",
> +		       tper->supported_features);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +static bool check_SUM(const void *data)
> +{
> +	const struct d0_single_user_mode *sum = data;
> +	u32 nlo = be32_to_cpu(sum->num_locking_objects);
> +
> +	if (nlo == 0) {
> +		pr_err("Need at least one locking object.\n");
> +		return false;
> +	}
> +
> +	pr_debug("Number of locking objects: %d\n", nlo);
> +
> +	return true;
> +}
> +
> +static u16 get_comID_v100(const void *data)
> +{
> +	const struct d0_opal_v100 *v100 = data;
> +
> +	return be16_to_cpu(v100->baseComID);
> +}
> +
> +static u16 get_comID_v200(const void *data)
> +{
> +	const struct d0_opal_v200 *v200 = data;
> +
> +	return be16_to_cpu(v200->baseComID);
> +}
> +
> +static int __opal_send_cmd(struct opal_suspend_unlk *data, u16 comID,
> +			   void *buffer, size_t buflen, sec_cb *cb,
> +			   void *cb_data)
> +{
> +	return data->ops.send(data->data, comID, TCG_SECP_01, buffer, buflen,
> +			     cb, cb_data);
> +}
> +static int _opal_send_cmd(struct block_device *bdev, u16 comID,
> +			  void *buffer, size_t buflen,
> +			  sec_cb *cb, void *cb_data)
> +{
> +	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
> +
> +	return ops->send(bdev->bd_disk->private_data, comID,
> +			 TCG_SECP_01, buffer, buflen,
> +			 cb, cb_data);
> +}
> +
> +static int __opal_recv_cmd(struct opal_suspend_unlk *data, u16 comID,
> +			   void *buffer, size_t buflen, sec_cb *cb,
> +			   void *cb_data)
> +{
> +	return data->ops.recv(data->data, comID, TCG_SECP_01, buffer, buflen,
> +			     cb, cb_data);
> +}
> +
> +static int _opal_recv_cmd(struct block_device *bdev, u16 comID,
> +			  void *buffer, size_t buflen,
> +			  sec_cb *cb, void *cb_data)
> +{
> +	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
> +
> +	return ops->recv(bdev->bd_disk->private_data, comID,
> +			 TCG_SECP_01, buffer, buflen,
> +			 cb, cb_data);
> +}
> +
> +static void opal_send_cb_cont(int error, void *data)
> +{
> +	struct opal_dev *dev = data;
> +	size_t buflen = IO_BUFFER_LENGTH;
> +	void *buffer = dev->cmd.resp;
> +	struct opal_header *hdr = buffer;
> +
> +	pr_debug("%s: Sent OPAL command: error=%d, outstanding=%d, minTransfer=%d\n",
> +	       dev->disk_name, error, hdr->cp.outstandingData,
> +	       hdr->cp.minTransfer);
> +
> +	if (error || hdr->cp.outstandingData == 0 ||
> +	    hdr->cp.minTransfer != 0) {
> +		if (dev->cmd.cb)
> +			dev->cmd.cb(error, dev->cmd.cb_data);
> +		return;
> +	}
> +
> +	memset(buffer, 0, buflen);
> +	if (dev->resume_from_suspend)
> +		__opal_recv_cmd(dev->resume_data, dev->comID,
> +				buffer, buflen, opal_send_cb_cont, dev);
> +	else
> +		_opal_recv_cmd(dev->bdev, dev->comID, buffer, buflen,
> +			       opal_send_cb_cont, dev);
> +}
> +
> +static void opal_send_cb(int error, void *data)
> +{
> +	struct opal_dev *dev = data;
> +	size_t buflen = IO_BUFFER_LENGTH;
> +	void *buffer = dev->cmd.resp;
> +
> +	if (error) {
> +		if (dev->cmd.cb)
> +			dev->cmd.cb(error, dev->cmd.cb_data);
> +		return;
> +	}
> +
> +	memset(buffer, 0, buflen);
> +	if (dev->resume_from_suspend)
> +		__opal_recv_cmd(dev->resume_data, dev->comID,
> +				buffer, buflen, opal_send_cb_cont, dev);
> +	else
> +		_opal_recv_cmd(dev->bdev, dev->comID, buffer, buflen,
> +			       opal_send_cb_cont, dev);
> +}
> +
> +static int opal_send_recv(struct opal_dev *dev, sec_cb *cb, void *cb_data)
> +{
> +	size_t buflen = IO_BUFFER_LENGTH;
> +	void *buffer = dev->cmd.cmd;
> +	int ret;
> +
> +	dev->cmd.cb = cb;
> +	dev->cmd.cb_data = cb_data;
> +	if (dev->resume_from_suspend)
> +		ret = __opal_send_cmd(dev->resume_data, dev->comID, buffer,
> +				      buflen, opal_send_cb, dev);
> +	else
> +		ret = _opal_send_cmd(dev->bdev, dev->comID, buffer, buflen,
> +				     opal_send_cb, dev);
> +
> +	return ret;
> +}
> +
> +static void check_geometry(struct opal_dev *dev, const void *data)
> +{
> +	const struct d0_geometry_features *geo = data;
> +
> +	dev->align = geo->alignment_granularity;
> +	dev->lowest_lba = geo->lowest_aligned_lba;
> +}
> +
> +static void opal_discovery0_end(int error, void *data)
> +{
> +	bool foundComID = false, supported = true, single_user = false;
> +	struct opal_dev *dev = data;
> +	const struct d0_header *hdr;
> +	const u8 *epos, *cpos;
> +	u16 comID = 0;
> +
> +	if (error) {
> +		pr_err("%s: Sending discovery0 failed\n", dev->disk_name);
> +		goto err_callback;
> +	}
> +
> +	epos = dev->cmd.resp;
> +	cpos = dev->cmd.resp;
> +	hdr = (struct d0_header *)dev->cmd.resp;
> +
> +	print_buffer(dev->cmd.resp, be32_to_cpu(hdr->length));
> +
> +	epos += be32_to_cpu(hdr->length); /* end of buffer */
> +	cpos += sizeof(*hdr); /* current position on buffer */
> +
> +	while (cpos < epos && supported) {
> +		const struct d0_features *body =
> +			(const struct d0_features *)cpos;
> +
> +		switch (be16_to_cpu(body->code)) {
> +		case FC_TPER:
> +			supported = check_tper(body->features);
> +			break;
> +		case FC_SINGLEUSER:
> +			single_user = check_SUM(body->features);
> +			break;
> +		case FC_GEOMETRY:
> +			check_geometry(dev, body);
> +			break;
> +		case FC_LOCKING:
> +		case FC_ENTERPRISE:
> +		case FC_DATASTORE:
> +			/* some ignored properties */
> +			pr_debug("%s: Found OPAL feature description: %d\n",
> +				 dev->disk_name, be16_to_cpu(body->code));
> +			break;
> +		case FC_OPALV100:
> +			comID = get_comID_v100(body->features);
> +			foundComID = true;
> +			break;
> +		case FC_OPALV200:
> +			comID = get_comID_v200(body->features);
> +			foundComID = true;
> +			break;
> +		default:
> +			if (be16_to_cpu(body->code) > 0xbfff) {
> +				/* vendor specific, just ignore */
> +			} else {
> +				pr_warn("%s: OPAL Unknown feature: %d\n",
> +					dev->disk_name, be16_to_cpu(body->code));
> +			}
Small nit, how about:

case 0xbfff ... 0xffff:
	/* vendor specific, just ignore */
	break;
default:
	pr_warn(...



> +		}
> +		cpos += body->length + 4;
> +	}
> +
> +	if (!supported) {
> +		pr_err("%s: Device not supported\n", dev->disk_name);
> +		goto err_callback;
> +	}
> +
> +	if (!single_user)
> +		pr_warn("%s: Device doesn't support single user mode\n",
> +			dev->disk_name);
> +
> +	if (!foundComID) {
> +		pr_warn("%s: Could not find OPAL comID for device. OPAL kernel unlocking will be disabled\n",
> +			dev->disk_name);
> +		goto err_callback;
> +	}
> +
> +	dev->comID = comID;
> +
> +err_callback:
> +	if (dev->oper_cb)
> +		dev->oper_cb(error, dev);
> +}
> +
> +static int opal_discovery0(struct opal_dev *dev)
> +{
> +	memset(dev->cmd.resp, 0, IO_BUFFER_LENGTH);
> +
> +	if (dev->resume_from_suspend)
> +		return __opal_recv_cmd(dev->resume_data, 0x0001,
> +				       dev->cmd.resp, IO_BUFFER_LENGTH,
> +				       opal_discovery0_end, dev);
> +
> +	return _opal_recv_cmd(dev->bdev, 0x0001, dev->cmd.resp,
> +			      IO_BUFFER_LENGTH, opal_discovery0_end,
> +			      dev);
> +}
> +
> +static void add_token_u8(struct opal_cmd *cmd, u8 tok)
> +{
> +	cmd->cmd[cmd->pos++] = tok;
> +}
> +
> +static ssize_t test_and_add_token_u8(struct opal_cmd *cmd, u8 tok)
> +{
> +	BUILD_BUG_ON(IO_BUFFER_LENGTH >= SIZE_MAX);
> +
> +	if (cmd->pos >= IO_BUFFER_LENGTH - 1) {
> +		pr_err("Error adding u8: end of buffer.\n");
> +		return -ERANGE;
> +	}
> +
> +	add_token_u8(cmd, tok);
> +
> +	return 1;
> +}
> +
> +#define TINY_ATOM_DATA_MASK GENMASK(5, 0)
> +#define TINY_ATOM_SIGNED BIT(6)
> +
> +#define SHORT_ATOM_ID BIT(7)
> +#define SHORT_ATOM_BYTESTRING BIT(5)
> +#define SHORT_ATOM_SIGNED BIT(4)
> +#define SHORT_ATOM_LEN_MASK GENMASK(3, 0)
> +
> +static void add_short_atom_header(struct opal_cmd *cmd, bool bytestring,
> +				  bool has_sign, int len)
> +{
> +	u8 atom;
> +
> +	atom = SHORT_ATOM_ID;
> +	atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
> +	atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
> +	atom |= len & SHORT_ATOM_LEN_MASK;
> +
> +	add_token_u8(cmd, atom);
> +}
> +
> +#define MEDIUM_ATOM_ID (BIT(7) | BIT(6))
> +#define MEDIUM_ATOM_BYTESTRING BIT(4)
> +#define MEDIUM_ATOM_SIGNED BIT(3)
> +#define MEDIUM_ATOM_LEN_MASK GENMASK(2, 0)
> +
> +static void add_medium_atom_header(struct opal_cmd *cmd, bool bytestring,
> +				   bool has_sign, int len)
> +{
> +	u8 header0;
> +
> +	header0 = MEDIUM_ATOM_ID;
> +	header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
> +	header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
> +	header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
> +	cmd->cmd[cmd->pos++] = header0;
> +	cmd->cmd[cmd->pos++] = len;
> +}
> +
> +static void add_token_u64(struct opal_cmd *cmd, u64 number, size_t len)
> +{
> +	add_short_atom_header(cmd, false, false, len);
> +
> +	while (len--) {
> +		u8 n = number >> (len * 8);
> +
> +		add_token_u8(cmd, n);
> +	}
> +}
> +
> +static ssize_t test_and_add_token_u64(struct opal_cmd *cmd, u64 number)
> +{
> +	int len;
> +	int msb;
> +
> +	if (!(number & ~TINY_ATOM_DATA_MASK))
> +		return test_and_add_token_u8(cmd, number);
> +
> +	msb = fls(number);
> +	len = DIV_ROUND_UP(msb, 4);
> +
> +	if (cmd->pos >= IO_BUFFER_LENGTH - len - 1) {
> +		pr_err("Error adding u64: end of buffer.\n");
> +		return -ERANGE;
> +	}
> +
> +	add_token_u64(cmd, number, len);
> +
> +	/* return length of token plus atom */
> +	return len + 1;
> +}
> +
> +static void add_token_bytestring(struct opal_cmd *cmd,
> +				 const u8 *bytestring, size_t len)
> +{
> +	memcpy(&cmd->cmd[cmd->pos], bytestring, len);
> +	cmd->pos += len;
> +}
> +
> +static ssize_t test_and_add_token_bytestring(struct opal_cmd *cmd,
> +					     const u8 *bytestring, size_t len)
> +{
> +	size_t header_len = 1;
> +	bool is_short_atom = true;
> +
> +	if (len & ~SHORT_ATOM_LEN_MASK) {
> +		header_len = 2;
> +		is_short_atom = false;
> +	}
> +
> +	if (cmd->pos >= IO_BUFFER_LENGTH - len - header_len) {
> +		pr_err("Error adding bytestring: end of buffer.\n");
> +		return -ERANGE;
> +	}
> +
> +	if (is_short_atom)
> +		add_short_atom_header(cmd, true, false, len);
> +	else
> +		add_medium_atom_header(cmd, true, false, len);
> +
> +	add_token_bytestring(cmd, bytestring, len);
> +
> +	return header_len + len;
> +}
> +
> +#define LOCKING_RANGE_NON_GLOBAL 0x03
> +
> +static int build_locking_range(u8 *buffer, size_t length, u8 lr)
> +{
> +	if (length < OPAL_UID_LENGTH)
> +		return -ERANGE;
> +
> +	memcpy(buffer, OPALUID[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
> +
> +	if (lr == 0)
> +		return 0;
> +	buffer[5] = LOCKING_RANGE_NON_GLOBAL;
> +	buffer[7] = lr;
> +
> +	return 0;
> +}
> +
> +static int build_locking_user(u8 *buffer, size_t length, u8 lr)
> +{
> +	if (length < OPAL_UID_LENGTH)
> +		return -ERANGE;
> +
> +	memcpy(buffer, OPALUID[OPAL_USER1_UID], OPAL_UID_LENGTH);
> +
> +	buffer[7] = lr + 1;
> +
> +	return 0;
> +}
> +
> +/*
> + * N = number of format specifiers (1-999) to be replicated
> + * c = u8
> + * u = u64
> + * s = bytestring, length
> + *
> + * ret = test_and_add_token_va(cmd, "c",
> + *			       u8_val1);
> + *
> + * ret = test_and_add_token_va(cmd, "2c2u",
> + *			       u8_val1, u8_val2, u64_val1, u64_val2);
> + *
> + * ret = test_and_add_token_va(cmd, "3s",
> + *			       bytestring1, length1,
> + *			       bytestring2, length2,
> + *			       bytestring3, length3);
> + */
> +static int test_and_add_token_va(struct opal_cmd *cmd,
> +				 const char *fmt, ...)
> +{
> +	const u8 *it = fmt, *tmp;
> +	int ret, num = 1, sum = 0;
> +	va_list ap;
> +
> +	va_start(ap, fmt);
> +
> +	while (*it != '\0') {
> +		u64 tok64 = 0;
> +		u8 tok, *bstr;
> +		size_t len;
> +
> +		ret = 0;
> +
> +		switch (*it) {
> +		case '1' ... '9':
> +			tmp = it;
> +			num = 0;
> +			while (*tmp >= '0' && *tmp <= '9')
> +				num = num * 10 + (*tmp++ - '0');
> +			it = tmp;
> +			continue;
> +		case 'c':
> +			while (num--) {
> +				tok = va_arg(ap, unsigned int);
> +				ret = test_and_add_token_u8(cmd, tok);
> +				if (ret < 0)
> +					goto err;
> +			}
> +			num = 1;
> +			break;
> +		case 'u':
> +			while (num--) {
> +				tok64 = va_arg(ap, u64);
> +				ret = test_and_add_token_u64(cmd, tok64);
> +				if (ret < 0)
> +					goto err;
> +			}
> +			num = 1;
> +			break;
> +		case 's':
> +			while (num--) {
> +				bstr = va_arg(ap, u8 *);
> +				len = va_arg(ap, size_t);
> +				ret = test_and_add_token_bytestring(cmd, bstr,
> +								    len);
> +				if (ret < 0)
> +					goto err;
> +			}
> +			num = 1;
> +			break;
> +		case ' ':
> +		case '\t':
> +			/* ignored */
> +			break;
> +		default:
> +			pr_warn("Unrecognized type.\n");
> +		}
> +
> +		it++;
> +		sum += ret;
> +	}
> +
> +	va_end(ap);
> +
> +	return sum;
> +
> + err:
> +	pr_err("Token failed to be added.\n");
> +	return ret;
> +}
> +
> +static void set_comID(struct opal_cmd *cmd, u16 comID)
> +{
> +	struct opal_header *hdr = (struct opal_header *)cmd->cmd;
> +
> +	hdr->cp.extendedComID[0] = comID >> 8;
> +	hdr->cp.extendedComID[1] = comID;
> +	hdr->cp.extendedComID[2] = 0;
> +	hdr->cp.extendedComID[3] = 0;
> +}
> +
> +static int cmd_finalize(struct opal_cmd *cmd, u32 hsn, u32 tsn)
> +{
> +	struct opal_header *hdr;
> +	int ret;
> +
> +	ret = test_and_add_token_va(cmd, "6c",
> +				    OPAL_ENDOFDATA, OPAL_STARTLIST,
> +				    0, 0, 0, OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("Error finalizing command.\n");
> +		return -EFAULT;
> +	}
> +
> +	hdr = (struct opal_header *) cmd->cmd;
> +
> +	hdr->pkt.TSN = cpu_to_be32(tsn);
> +	hdr->pkt.HSN = cpu_to_be32(hsn);
> +
> +	hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
> +	while (cmd->pos % 4) {
> +		if (cmd->pos >= IO_BUFFER_LENGTH) {
> +			pr_err("Error: Buffer overrun\n");
> +			return -ERANGE;
> +		}
> +		cmd->cmd[cmd->pos++] = 0;
> +	}
> +	hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
> +				      sizeof(hdr->pkt));
> +	hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
> +
> +	return 0;
> +}
> +
> +static enum OPAL_RESPONSE_TOKEN token_type(const struct parsed_resp *resp,
> +					   int n)
> +{
> +	const struct opal_resp_tok *tok;
> +
> +	if (n >= resp->num) {
> +		pr_err("Token number doesn't exist: %d, resp: %d\n",
> +		       n, resp->num);
> +		return OPAL_DTA_TOKENID_INVALID;
> +	}
> +
> +	tok = &resp->toks[n];
> +	if (tok->len == 0) {
> +		pr_err("Token length must be non-zero\n");
> +		return OPAL_DTA_TOKENID_INVALID;
> +	}
> +
> +	return tok->type;
> +}
> +
> +/*
> + * This function returns 0 in case of invalid token. One should call
> + * token_type() first to find out if the token is valid or not.
> + */
> +static enum OPAL_TOKEN response_get_token(const struct parsed_resp *resp,
> +					  int n)
> +{
> +	const struct opal_resp_tok *tok;
> +
> +	if (n >= resp->num) {
> +		pr_err("Token number doesn't exist: %d, resp: %d\n",
> +		       n, resp->num);
> +		return 0;
> +	}
> +
> +	tok = &resp->toks[n];
> +	if (tok->len == 0) {
> +		pr_err("Token length must be non-zero\n");
> +		return 0;
> +	}
> +
> +	return tok->pos[0];
> +}
> +
> +static size_t response_parse_tiny(struct opal_resp_tok *tok,
> +				  const u8 *pos)
> +{
> +	tok->pos = pos;
> +	tok->len = 1;
> +	tok->width = OPAL_WIDTH_TINY;
> +
> +	if (pos[0] & TINY_ATOM_SIGNED) {
> +		tok->type = OPAL_DTA_TOKENID_SINT;
> +	} else {
> +		tok->type = OPAL_DTA_TOKENID_UINT;
> +		tok->stored.u = pos[0] & 0x3f;
> +	}
> +
> +	return tok->len;
> +}
> +
> +static size_t response_parse_short(struct opal_resp_tok *tok,
> +				   const u8 *pos)
> +{
> +	tok->pos = pos;
> +	tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
> +	tok->width = OPAL_WIDTH_SHORT;
> +
> +	if (pos[0] & SHORT_ATOM_BYTESTRING) {
> +		tok->type = OPAL_DTA_TOKENID_BYTESTRING;
> +	} else if (pos[0] & SHORT_ATOM_SIGNED) {
> +		tok->type = OPAL_DTA_TOKENID_SINT;
> +	} else {
> +		u64 u_integer = 0;
> +		int i, b = 0;
> +
> +		tok->type = OPAL_DTA_TOKENID_UINT;
> +		if (tok->len > 9)
Should this be len > 8 or len >= 9 ?

> +			pr_warn("uint64 with more than 8 bytes\n");
> +		for (i = tok->len - 1; i > 0; i--) {
> +			u_integer |= ((u64)pos[i] << (8 * b));
> +			b++;
> +		}
It doesn't look particularly safe to keep using this driver on a drive
if it returns a len > 8. But the specs do allow 16-byte data in a short
atom, so maybe we should bail on allowing the driver to manage the
drive, or change the types to some 16-byte type?

> +		tok->stored.u = u_integer;
> +	}
> +
> +	return tok->len;
> +}
> +
> +static size_t response_parse_medium(struct opal_resp_tok *tok,
> +				    const u8 *pos)
> +{
> +	tok->pos = pos;
> +	tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
> +	tok->width = OPAL_WIDTH_MEDIUM;
> +
> +	if (pos[0] & MEDIUM_ATOM_BYTESTRING)
> +		tok->type = OPAL_DTA_TOKENID_BYTESTRING;
> +	else if (pos[0] & MEDIUM_ATOM_SIGNED)
> +		tok->type = OPAL_DTA_TOKENID_SINT;
> +	else
> +		tok->type = OPAL_DTA_TOKENID_UINT;
> +
> +	return tok->len;
> +}
> +
> +#define LONG_ATOM_ID (BIT(7) | BIT(6) | BIT(5))
> +#define LONG_ATOM_BYTESTRING BIT(1)
> +#define LONG_ATOM_SIGNED BIT(0)
> +static size_t response_parse_long(struct opal_resp_tok *tok,
> +				  const u8 *pos)
> +{
> +	tok->pos = pos;
> +	tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
> +	tok->width = OPAL_WIDTH_LONG;
> +
> +	if (pos[0] & LONG_ATOM_BYTESTRING)
> +		tok->type = OPAL_DTA_TOKENID_BYTESTRING;
> +	else if (pos[0] & LONG_ATOM_SIGNED)
> +		tok->type = OPAL_DTA_TOKENID_SINT;
> +	else
> +		tok->type = OPAL_DTA_TOKENID_UINT;
> +
> +	return tok->len;
> +}
> +
> +static size_t response_parse_token(struct opal_resp_tok *tok,
> +				   const u8 *pos)
> +{
> +	tok->pos = pos;
> +	tok->len = 1;
> +	tok->type = OPAL_DTA_TOKENID_TOKEN;
> +	tok->width = OPAL_WIDTH_TOKEN;
> +
> +	return tok->len;
> +}
> +
> +static int response_parse(const u8 *buf, size_t length,
> +			  struct parsed_resp *resp)
> +{
> +	const struct opal_header *hdr;
> +	struct opal_resp_tok *iter;
> +	int ret, num_entries = 0;
> +	u32 cpos = 0, total;
> +	size_t token_length;
> +	const u8 *pos;
> +
> +	if (!buf)
> +		return -EFAULT;
> +
> +	if (!resp)
> +		return -EFAULT;
> +
> +	hdr = (struct opal_header *)buf;
> +	pos = buf;
> +	pos += sizeof(*hdr);
> +
> +	pr_debug("Response size: cp: %d, pkt: %d, subpkt: %d\n",
> +		 be32_to_cpu(hdr->cp.length),
> +		 be32_to_cpu(hdr->pkt.length),
> +		 be32_to_cpu(hdr->subpkt.length));
> +
> +	if ((hdr->cp.length == 0)
> +	    || (hdr->pkt.length == 0)
> +	    || (hdr->subpkt.length == 0)) {
> +		pr_err("Bad header length. cp: %d, pkt: %d, subpkt: %d\n",
> +		       be32_to_cpu(hdr->cp.length),
> +		       be32_to_cpu(hdr->pkt.length),
> +		       be32_to_cpu(hdr->subpkt.length));
> +		print_buffer(pos, sizeof(*hdr));
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +
> +	if (pos > buf + length) {
> +		ret = -EFAULT;
> +		goto err;
> +	}
> +
> +	iter = resp->toks;
> +	total = be32_to_cpu(hdr->subpkt.length);
> +	print_buffer(pos, total);
> +	while (cpos < total) {
> +		if (!(pos[0] & 0x80)) /* tiny atom */
> +			token_length = response_parse_tiny(iter, pos);
> +		else if (!(pos[0] & 0x40)) /* short atom */
> +			token_length = response_parse_short(iter, pos);
> +		else if (!(pos[0] & 0x20)) /* medium atom */
> +			token_length = response_parse_medium(iter, pos);
> +		else if (!(pos[0] & 0x10)) /* long atom */
> +			token_length = response_parse_long(iter, pos);
> +		else /* TOKEN */
> +			token_length = response_parse_token(iter, pos);
> +
> +		pos += token_length;
> +		cpos += token_length;
> +		iter++;
> +		num_entries++;
> +	}
> +
> +	if (num_entries == 0) {
> +		pr_err("Couldn't parse response.\n");
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +	resp->num = num_entries;
> +
> +	return 0;
> +err:
> +	return ret;
> +}
> +
> +static size_t response_get_string(const struct parsed_resp *resp, int n,
> +				  const char **store)
> +{
> +	*store = NULL;
> +	if (!resp) {
> +		pr_err("Response is NULL\n");
> +		return 0;
> +	}
> +
> +	if (n > resp->num) {
> +		pr_err("Response has %d tokens. Can't access %d\n",
> +		       resp->num, n);
> +		return 0;
> +	}
> +
> +	if (resp->toks[n].type != OPAL_DTA_TOKENID_BYTESTRING) {
> +		pr_err("Token is not a byte string!\n");
> +		return 0;
> +	}
> +
> +	*store = resp->toks[n].pos + 1;
> +	return resp->toks[n].len - 1;
> +}
> +
> +static u64 response_get_u64(const struct parsed_resp *resp, int n)
> +{
> +	if (!resp) {
> +		pr_err("Response is NULL\n");
> +		return 0;
> +	}
> +
> +	if (n > resp->num) {
> +		pr_err("Response has %d tokens. Can't access %d\n",
> +		       resp->num, n);
> +		return 0;
> +	}
> +
> +	if (resp->toks[n].type != OPAL_DTA_TOKENID_UINT) {
> +		pr_err("Token is not unsigned it: %d\n",
> +		       resp->toks[n].type);
> +		return 0;
> +	}
> +
> +	if (!((resp->toks[n].width == OPAL_WIDTH_TINY) ||
> +	      (resp->toks[n].width == OPAL_WIDTH_SHORT))) {
> +		pr_err("Atom is not short or tiny: %d\n",
> +		       resp->toks[n].width);
> +		return 0;
> +	}
> +
> +	return resp->toks[n].stored.u;
> +}
> +
> +static u8 response_status(const struct parsed_resp *resp)
> +{
> +	if ((token_type(resp, 0) == OPAL_DTA_TOKENID_TOKEN)
> +	    && (response_get_token(resp, 0) == OPAL_ENDOFSESSION)) {
> +		return 0;
> +	}
> +
> +	if (resp->num < 5)
> +		return DTAERROR_NO_METHOD_STATUS;
> +
> +	if ((token_type(resp, resp->num - 1) != OPAL_DTA_TOKENID_TOKEN) ||
> +	    (token_type(resp, resp->num - 5) != OPAL_DTA_TOKENID_TOKEN) ||
> +	    (response_get_token(resp, resp->num - 1) != OPAL_ENDLIST) ||
> +	    (response_get_token(resp, resp->num - 5) != OPAL_STARTLIST))
> +		return DTAERROR_NO_METHOD_STATUS;
> +
> +	return response_get_u64(resp, resp->num - 4);
> +}
> +
> +/* Parses and checks for errors */
> +static int parse_and_check_status(struct opal_dev *dev)
> +{
> +	struct opal_cmd *cmd;
> +	int error;
> +
> +	cmd = &dev->cmd;
> +	print_buffer(cmd->cmd, cmd->pos);
> +
> +	error = response_parse(cmd->resp, IO_BUFFER_LENGTH, &dev->parsed);
> +	if (error) {
> +		pr_err("%s: Couldn't parse response.\n", dev->disk_name);
> +		goto err_return;
> +	}
> +
> +	error = response_status(&dev->parsed);
> +	if (error)
> +		pr_err("%s: Response Status: %d\n", dev->disk_name,
> +		       error);
> +
> + err_return:
> +	return error;
> +}
> +
> +static void clear_opal_cmd(struct opal_cmd *cmd)
> +{
> +	cmd->pos = sizeof(struct opal_header);
> +	memset(cmd->cmd, 0, IO_BUFFER_LENGTH);
> +	cmd->cb = NULL;
> +	cmd->cb_data = NULL;
> +}
> +
> +static void start_opal_session_cont(int error, void *data)
> +{
> +	struct opal_dev *dev = data;
> +	u32 HSN, TSN;
> +
> +	if (error)
> +		goto err_return;
> +
> +	error = parse_and_check_status(dev);
> +	if (error)
> +		goto err_return;
> +
> +	HSN = response_get_u64(&dev->parsed, 4);
> +	TSN = response_get_u64(&dev->parsed, 5);
> +
> +	if (HSN == 0 && TSN == 0) {
> +		pr_err("%s: Couldn't authenticate session\n", dev->disk_name);
> +		error = -EPERM;
> +		goto err_return;
> +	}
> +
> +	dev->HSN = HSN;
> +	dev->TSN = TSN;
> +
> +err_return:
> +	if (dev->oper_cb)
> +		dev->oper_cb(error, dev);
> +}
> +
> +static int get_opal_key(struct opal_dev *dev)
> +{
> +	struct key *ukey = NULL;
> +	const u8 *tmpkey = NULL;
> +	size_t tmplen;
> +	int ret = 0;
> +
> +	if (dev->key_type == OPAL_KEY_PLAIN) {
> +		tmpkey = dev->key_name;
> +		tmplen = dev->key_name_len;
> +	} else if (dev->key_type == OPAL_KEY_KEYRING) {
> +		ukey = request_user_key(dev->key_name, &tmpkey, &tmplen);
> +		if (IS_ERR(ukey)) {
> +			pr_err("%s: Can't retrieve key: %ld\n", dev->disk_name,
> +			       PTR_ERR(ukey));
> +			return PTR_ERR(ukey);
> +		}
> +	} else {
> +		pr_err("Requested invalid key type: %d\n", dev->key_type);
> +		return -EINVAL;
> +	}
> +
> +	if (tmplen > OPAL_KEY_MAX) {
> +		pr_err("Requested key with invalid size: %zd\n", tmplen);
> +		ret = -EINVAL;
> +		goto err_exit;
> +	}
> +
> +	dev->key_len = tmplen;
> +	if (!memcpy(dev->key, tmpkey, tmplen)) {
> +		pr_err("Error when copying key");
> +		ret = -EFAULT;
> +		goto err_exit;
> +	}
> +
> +err_exit:
> +	key_put(ukey);
> +
> +	return 0;
> +}
> +
> +static void clean_opal_key(struct opal_dev *dev)
> +{
> +	memset(dev->key, 0, OPAL_KEY_MAX);
> +	dev->key_len = 0;
> +}
> +
> +static inline void clean_function_data(struct opal_dev *dev)
> +{
> +		dev->func_data = NULL;
> +		dev->num_func_data = 0;
> +}
> +
> +/* This is a generic continue fn.
> + * We use this when we don't care about the response data
> + * and simply want to check the status and continue.
> + */
> +static void generic_cont(int error, void *data)
> +{
> +	struct opal_dev *dev = data;
> +
> +	if (error)
> +		goto err_return;
> +
> +	error = parse_and_check_status(dev);
> +
> + err_return:
> +	if (dev->oper_cb)
> +		dev->oper_cb(error, dev);
> +}

How about:

static void generic_cont(int error, void *data)
{
	struct opal_dev *dev = data;

	if (!error)
		error = parse_and_check_status(dev);

	if (dev->oper_cb)
		dev->oper_cb(error, dev);
}

> +
> +static void end_session_cont(int error, void *data)
> +{
> +	struct opal_dev *dev = data;
> +
> +	dev->HSN = 0;
> +	dev->TSN = 0;
> +	generic_cont(error, data);
> +}
> +
> +static int finalize_and_send(struct opal_dev *dev, struct opal_cmd *cmd,
> +			     sec_cb cont)
> +{
> +	int ret;
> +
> +	ret = cmd_finalize(cmd, dev->HSN, dev->TSN);
> +	if (ret) {
> +		pr_err("%s: Error finalizing command buffer: %d\n",
> +		       dev->disk_name, ret);
> +		return ret;
> +	}
> +
> +	print_buffer(cmd->cmd, cmd->pos);
> +
> +	ret = opal_send_recv(dev, cont, dev);
> +	if (ret)
> +		pr_err("%s: Error running command: %d\n",
> +		       dev->disk_name, ret);
> +
> +	return ret;
> +}
> +
> +static int wait_for_cmd_completion(struct opal_completion *completion)
> +{
> +	wait_for_completion_interruptible(&completion->cmd_completion);
> +	return completion->completion_status;
> +}
> +
> +static int gen_key(struct opal_dev *dev)
> +{
> +	const u8 *method;
> +	u8 uid[OPAL_UID_LENGTH];
> +	struct opal_cmd *cmd;
> +	int ret;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
> +	method = OPALMETHOD[OPAL_GENKEY];
> +	kfree(dev->prev_data);
> +	dev->prev_data = NULL;
> +
> +	ret = test_and_add_token_va(cmd, "c2s 2c",
> +				    OPAL_CALL,
> +				    uid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_ENDLIST);
> +	if (ret < 0) {
> +		pr_err("%s: Error building gen key command\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +static void get_active_key_cont(int error, void *data)
> +{
> +	struct opal_dev *dev = data;
> +	const char *activekey;
> +	size_t keylen;
> +
> +	if (error)
> +		goto err_return;
> +
> +	error = parse_and_check_status(dev);
> +	if (error)
> +		goto err_return;
> +	keylen = response_get_string(&dev->parsed, 4, &activekey);
> +	if (!activekey) {
> +		pr_err("%s: Couldn't extract the Activekey from the response\n",
> +		       __func__);
> +		error = 0x0A;
> +		goto err_return;
> +	}
> +	dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
> +
> +	if (!dev->prev_data)
> +		error = -ENOMEM;
> +
> +	dev->prev_d_len = keylen;
> +
> +err_return:
> +	if (dev->oper_cb)
> +		dev->oper_cb(error, dev);
> +}
> +
> +static int get_active_key(struct opal_dev *dev)
> +{
> +	const u8 *method;
> +	u8 uid[OPAL_UID_LENGTH];
> +	struct opal_cmd *cmd;
> +	int ret;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	method = OPALMETHOD[OPAL_GET];
> +
> +	ret = build_locking_range(uid, sizeof(uid), dev->lr);
> +	if (ret < 0) {
> +		pr_err("%s: Can't build locking range\n", dev->disk_name);
> +		return -EINVAL;
> +	}
> +
> +	ret = test_and_add_token_va(cmd, "c2s 6c 4c 2c",
> +				    OPAL_CALL,
> +				    uid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_03, /* startCloumn */
> +				    OPAL_TINY_UINT_10, /* ActiveKey */
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_04, /* endColumn */
> +				    OPAL_TINY_UINT_10, /* ActiveKey */
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_ENDLIST,
> +				    OPAL_ENDLIST);
> +	if (ret < 0) {
> +		pr_err("%s: Error building get active key command\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, get_active_key_cont);
> +}
> +
> +static int setup_locking_range(struct opal_dev *dev)
> +{
> +	const u8 *method;
> +	u8 uid[OPAL_UID_LENGTH];
> +	struct opal_cmd *cmd;
> +	struct opal_user_lr_setup *setup;
> +	int ret;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	method = OPALMETHOD[OPAL_SET];
> +	ret = build_locking_range(uid, sizeof(uid), dev->lr);
> +	if (ret < 0) {
> +		pr_err("%s: Can't build locking range\n", dev->disk_name);
> +		return -EINVAL;
> +	}
> +	setup = dev->func_data[dev->state - 1];
> +
> +	ret = test_and_add_token_va(cmd, "c2s  4c 2cuc 2cuc 2cuc 2cu 4c",
> +				    OPAL_CALL,
> +				    uid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_VALUES,
> +				    OPAL_STARTLIST,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_03, /* Range Start */
> +				    setup->range_start,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_04, /* Range Length */
> +				    setup->range_length,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_05, /* ReadLockEnabled */
> +				    !!setup->RLE,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_06, /* WriteLockEnabled */
> +				    !!setup->WLE,
> +
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST,
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST);
> +	if (ret < 0) {
> +		pr_err("%s: Error building Setup Locking range command.\n",
> +		       dev->disk_name);
> +		return ret;
> +
> +	}
> +
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +static int start_adminsp_opal_session(struct opal_dev *dev,
> +				      enum OPAL_UID auth,
> +				      const char *key,
> +				      u8 key_len)
> +{
> +	const u8 *method, *smuid, *admin_sp, *hsa;
> +	struct opal_cmd *cmd;
> +	u32 HSN;
> +	int ret;
> +
> +	if (key == NULL && auth != OPAL_ANYBODY_UID) {
> +		pr_err("%s: Attempted to open ADMIN_SP Session without a Host" \
> +		       "Challenge, and not as the Anybody UID\n", __func__);
> +		return 1;
> +	}
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +
> +	set_comID(cmd, dev->comID);
> +	HSN = 0x41;
> +
> +	smuid = OPALUID[OPAL_SMUID_UID];
> +	method = OPALMETHOD[OPAL_STARTSESSION];
> +	admin_sp = OPALUID[OPAL_ADMINSP_UID];
> +
> +	ret = test_and_add_token_va(cmd, "c2s cusc",
> +				    OPAL_CALL,
> +				    smuid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +				    OPAL_STARTLIST,
> +				    HSN,
> +				    admin_sp, OPAL_UID_LENGTH,
> +				    OPAL_TINY_UINT_01);
> +	if (ret < 0) {
> +		pr_err("%s: Error building start adminsp session command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	switch (auth) {
> +	case OPAL_ANYBODY_UID:
> +		/* nothing left to do for anybody, just end and finalize */
> +		ret = test_and_add_token_va(cmd, "c",
> +					    OPAL_ENDLIST);
> +		break;
> +	case OPAL_SID_UID:
> +		hsa = OPALUID[OPAL_SID_UID];
> +		ret = test_and_add_token_va(cmd, "2c s 3c s 2c",
> +					    OPAL_STARTNAME,
> +					    OPAL_TINY_UINT_00, /* HostChallenge */
> +					    key, key_len,
> +					    OPAL_ENDNAME,
> +					    OPAL_STARTNAME,
> +					    OPAL_TINY_UINT_03, /* HostSignAuth */
> +					    hsa, OPAL_UID_LENGTH,
> +					    OPAL_ENDNAME,
> +					    OPAL_ENDLIST);
> +		break;
> +	default:
> +		pr_err("Cannot start Admin SP session with auth %d\n", auth);
> +		return 1;
> +	}
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error building start adminsp session command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, start_opal_session_cont);
> +}
> +
> +static int start_anybodyASP_opal_session(struct opal_dev *dev)
> +{
> +	return start_adminsp_opal_session(dev, OPAL_ANYBODY_UID, NULL, 0);
> +}
> +
> +static int start_SIDASP_opal_session(struct opal_dev *dev)
> +{
> +	int ret;
> +	const u8 *key = dev->prev_data;
> +
> +	if (!key)
> +		ret = start_adminsp_opal_session(dev, OPAL_SID_UID, dev->key,
> +						 dev->key_len);
> +	else {
> +		ret = start_adminsp_opal_session(dev, OPAL_SID_UID, key,
> +						 dev->prev_d_len);
> +		kfree(key);
> +		dev->prev_data = NULL;
> +	}
> +	return ret;
> +}
> +
> +static int start_lockingsp_opal_session(struct opal_dev *dev,
> +					enum OPAL_UID auth, const u8 *key,
> +					u8 key_len)
> +{
> +
> +	const u8 *method, *smuid, *locking_sp, *hsa;
> +	struct opal_cmd *cmd;
> +	size_t klen = key_len;
> +	u32 HSN;
> +	int ret;
> +
> +	if (key == NULL) {
> +		pr_err("Cannot start Locking SP session without a key\n");
> +		return -EINVAL;
> +	}
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +
> +	set_comID(cmd, dev->comID);
> +	HSN = 0x41;
> +
> +	smuid = OPALUID[OPAL_SMUID_UID];
> +	method = OPALMETHOD[OPAL_STARTSESSION];
> +	locking_sp = OPALUID[OPAL_LOCKINGSP_UID];
> +	hsa = OPALUID[auth];
> +
> +	ret = test_and_add_token_va(cmd, "c2s cusc 2csc 2csc c",
> +				    OPAL_CALL,
> +				    smuid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    HSN,
> +				    locking_sp, OPAL_UID_LENGTH,
> +				    OPAL_TINY_UINT_01,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_00, /* HostChallenge */
> +				    key, klen,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_03, /* Host Sign Authority */
> +				    hsa, OPAL_UID_LENGTH,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error building start adminsp session command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +	return finalize_and_send(dev, cmd, start_opal_session_cont);
> +}
> +
> +static inline int start_admin1LSP_opal_session(struct opal_dev *dev)
> +{
> +	return start_lockingsp_opal_session(dev, OPAL_ADMIN1_UID,
> +					    dev->key, dev->key_len);
> +}
> +
> +static int start_auth_opal_session(struct opal_dev *dev)
> +{
> +	const u8 *method, *smuid, *locking_sp;
> +	u8 lk_ul_user[OPAL_UID_LENGTH];
> +	struct opal_cmd *cmd;
> +	u32 HSN;
> +	int ret;
> +	struct opal_user_info *uinfo;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +
> +	set_comID(cmd, dev->comID);
> +
> +	HSN = 0x41;
Can we #define this; it's used a few other places and is magicky

> +
> +	uinfo = dev->func_data[dev->state - 1];
> +
> +	smuid = OPALUID[OPAL_SMUID_UID];
> +	method = OPALMETHOD[OPAL_STARTSESSION];
> +	locking_sp = OPALUID[OPAL_LOCKINGSP_UID];
> +
> +	if (uinfo->SUM) {
> +		ret = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
> +					 dev->lr);
> +		if (ret < 0) {
> +			pr_err("%s: Can't build locking user\n",
> +			       dev->disk_name);
> +			return ret;
> +		}
> +	} else if (uinfo->who != OPAL_ADMIN1 && !uinfo->SUM) {
> +		ret = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
> +					 uinfo->who - 1);
> +		if (ret < 0) {
> +			pr_err("%s: Can't build locking user\n",
> +			       dev->disk_name);
> +			return ret;
> +		}
> +	} else
> +		memcpy(lk_ul_user, OPALUID[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
> +
> +
> +	ret = test_and_add_token_va(cmd, "c2s cus3cs3c s 2c",
> +				    OPAL_CALL,
> +				    smuid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    HSN,
> +				    locking_sp, OPAL_UID_LENGTH,
> +				    OPAL_TINY_UINT_01,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_00,
> +				    dev->key, dev->key_len,
> +				    OPAL_ENDNAME,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_03,
> +
> +				    lk_ul_user, OPAL_UID_LENGTH,
> +
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error building STARTSESSION command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, start_opal_session_cont);
> +}
> +
> +static int revert_tper(struct opal_dev *dev)
> +{
> +	const u8 *method, *smuid;
> +	struct opal_cmd *cmd;
> +	int ret;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +
> +	set_comID(cmd, dev->comID);
> +
> +	smuid = OPALUID[OPAL_ADMINSP_UID];
> +	method = OPALMETHOD[OPAL_REVERT];
> +
> +	ret = test_and_add_token_va(cmd, "c2s 2c",
> +				    OPAL_CALL,
> +				    smuid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +				    OPAL_STARTLIST,
> +				    OPAL_ENDLIST);
> +	if (ret < 0) {
> +		pr_err("%s: Error building REVERT TPER command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +static int internal_activate_user(struct opal_dev *dev)
> +{
> +	const u8 *method;
> +	u8 uid[OPAL_UID_LENGTH];
> +	struct opal_cmd *cmd;
> +	int ret;
> +	struct opal_activate_user *act;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	act = dev->func_data[dev->state - 1];
> +
> +	memcpy(uid, OPALUID[OPAL_USER1_UID], OPAL_UID_LENGTH);
> +	uid[7] = act->who.who;
> +
> +	method = OPALMETHOD[OPAL_SET];
> +
> +	ret = test_and_add_token_va(cmd, "c2s 3c c 4c 3c",
> +				    OPAL_CALL,
> +				    uid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_01, /* Values */
> +
> +				    OPAL_STARTLIST,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_05, /* Enabled */
> +				    OPAL_TINY_UINT_01, /* True */
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_ENDLIST,
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error building Activate UserN command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +static int erase_locking_range(struct opal_dev *dev)
> +{
> +	const u8 *method;
> +	u8 uid[OPAL_UID_LENGTH];
> +	struct opal_cmd *cmd;
> +	int ret;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	method = OPALMETHOD[OPAL_ERASE];
> +
> +	if (build_locking_range(uid, sizeof(uid), dev->lr) < 0) {
> +		pr_err("%s: Can't build locking range\n", dev->disk_name);
> +		return -EINVAL;
> +	}
> +
> +	ret = test_and_add_token_va(cmd, "c2s 2c",
> +				    OPAL_CALL,
> +				    uid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error building Erase Locking Range Cmmand.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +static int set_mbr_done(struct opal_dev *dev)
> +{
> +	const u8 *method, *uid;
> +	struct opal_cmd *cmd;
> +	int ret;
> +
> +	u8 mbr_done_tf = *(u8 *)dev->func_data[dev->state - 1];
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	method = OPALMETHOD[OPAL_SET];
> +	uid = OPALUID[OPAL_MBRCONTROL];
> +
> +	ret = test_and_add_token_va(cmd, "c2s 3c 6c 2c",
> +				    OPAL_CALL,
> +				    uid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_VALUES,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_02, /* Done */
> +				    mbr_done_tf,       /* Done T or F */
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST,
> +
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST);
> +	if (ret < 0) {
> +		pr_err("%s: Error Building set MBR Dont/Not done command\n",
s/Dont/Done/ ?


> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +static int set_mbr_enable_disable(struct opal_dev *dev)
> +{
> +	const u8 *method, *uid;
> +	struct opal_cmd *cmd;
> +	int ret;
> +
> +	u8 mbr_en_dis = *(u8 *)dev->func_data[dev->state - 1];
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	method = OPALMETHOD[OPAL_SET];
> +	uid = OPALUID[OPAL_MBRCONTROL];
> +
> +	ret = test_and_add_token_va(cmd, "c2s 3c 6c 2c",
> +				    OPAL_CALL,
> +				    uid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_VALUES,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_01, /* Enable */
> +				    mbr_en_dis,        /* Enable or Disable */
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST,
> +
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST);
> +	if (ret < 0) {
> +		pr_err("%s: Error Building set MBR Dont/Not done command\n",
s/Dont/Done/ ?


> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +static int set_new_pw(struct opal_dev *dev)
> +{
> +	const u8 *method;
> +	u8 cpin_uid[OPAL_UID_LENGTH];
> +	struct opal_cmd *cmd;
> +	int ret;
> +	struct opal_new_pw *pw;
> +	size_t key_len;
> +	u8 *key;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	pw = dev->func_data[dev->state - 1];
> +	key = pw->new_pin.key;
> +	key_len = pw->new_pin.key_len;
> +	memcpy(cpin_uid, OPALUID[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
> +
> +	if (pw->user_for_pw != OPAL_ADMIN1) {
> +		cpin_uid[5] = 0x03;
> +		if (pw->who.SUM)
> +			cpin_uid[7] = pw->new_pin.lr + 1;
> +		else
> +			cpin_uid[7] = pw->user_for_pw;
> +	}
> +
> +	method = OPALMETHOD[OPAL_SET];
> +
> +	ret = test_and_add_token_va(cmd, "c2s 3c 3cs2c 2c",
> +				    OPAL_CALL,
> +				    cpin_uid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_01, /* Values */
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_03, /* PIN */
> +				    key, key_len,
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST,
> +
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error building SET AMIN1 PIN command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +static int set_sid_cpin_pin(struct opal_dev *dev)
> +{
> +	const u8 *method, *cpin_uid;
> +	struct opal_cmd *cmd;
> +	int ret;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	cpin_uid = OPALUID[OPAL_C_PIN_SID];
> +	method = OPALMETHOD[OPAL_SET];
> +
> +	ret = test_and_add_token_va(cmd, "c2s 2c 4cs2c 2c",
> +				    OPAL_CALL,
> +				    cpin_uid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +
> +				    OPAL_TINY_UINT_01, /* Values */
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_03, /* PIN */
> +				    dev->key, dev->key_len,
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST,
> +
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error building SET CPIN PIN command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +static void query_locking_range_cont(int error, void *data)
> +{
> +	struct opal_dev *dev = data;
> +
> +	if (error)
> +		goto err_return;
> +
> +	error = parse_and_check_status(dev);
> +	if (error)
> +		goto err_return;
> +
> +	dev->start = response_get_u64(&dev->parsed, 4);
> +	dev->length = response_get_u64(&dev->parsed, 8);
> +
> +err_return:
> +	if (dev->oper_cb)
> +		dev->oper_cb(error, dev);
> +}
> +
> +static int query_locking_range(struct opal_dev *dev)
> +{
> +	u8 lr_buffer[OPAL_UID_LENGTH];
> +	struct opal_cmd *cmd;
> +	const u8 *method;
> +	int ret;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +
> +	method = OPALMETHOD[OPAL_GET];
> +
> +	if (build_locking_range(lr_buffer, sizeof(lr_buffer), dev->lr) < 0) {
> +		pr_err("%s: Can't build locking range\n", dev->disk_name);
> +		return -EINVAL;
> +	}
> +
> +	set_comID(cmd, dev->comID);
> +
> +	ret = test_and_add_token_va(cmd, "c2s 12c",
> +				    OPAL_CALL,
> +				    lr_buffer, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_STARTCOLUMN,
> +				    OPAL_RANGESTART,
> +				    OPAL_ENDNAME,
> +				    OPAL_STARTNAME,
> +				    OPAL_ENDCOLUMN,
> +				    OPAL_RANGELENGTH,
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST,
> +				    OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error building GET Locking Range command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, query_locking_range_cont);
> +}
> +
> +static int add_user_to_lr(struct opal_dev *dev)
> +{
> +	u8 lr_buffer[OPAL_UID_LENGTH];
> +	u8 user_uid[OPAL_UID_LENGTH];
> +	struct opal_cmd *cmd;
> +	const u8 *method;
> +	struct opal_lock_unlock *lkul;
> +	int ret;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	method = OPALMETHOD[OPAL_SET];
> +
> +	lkul = dev->func_data[dev->state - 1];
> +
> +	memcpy(lr_buffer, OPALUID[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
> +	       OPAL_UID_LENGTH);
> +
> +	if (lkul->l_state == OPAL_RW)
> +		memcpy(lr_buffer, OPALUID[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
> +		       OPAL_UID_LENGTH);
> +
> +	lr_buffer[7] = dev->lr;
> +
> +	memcpy(user_uid, OPALUID[OPAL_USER1_UID], OPAL_UID_LENGTH);
> +	user_uid[7] = lkul->authority.who;
> +
> +	ret = test_and_add_token_va(cmd, "c2s 3c 3c 2c 2sc c2sc cs2c 5c",
> +				    OPAL_CALL,
> +				    lr_buffer, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_01, /* Values */
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_03, /* BooleanExpr */
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +
> +				    OPALUID[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
> +				    OPAL_UID_LENGTH_HALF,
> +				    user_uid, OPAL_UID_LENGTH,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPALUID[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
> +				    OPAL_UID_LENGTH_HALF,
> +				    user_uid, OPAL_UID_LENGTH,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPALUID[OPAL_HALF_UID_BOOLEAN_ACE],
> +				    OPAL_UID_LENGTH_HALF,
> +				    OPAL_TINY_UINT_01,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_ENDLIST,
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST,
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST);
> +	if (ret < 0) {
> +		pr_err("%s: Error building add user to locking range command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +static int lock_unlock_locking_range(struct opal_dev *dev)
> +{
> +	u8 lr_buffer[OPAL_UID_LENGTH];
> +	struct opal_cmd *cmd;
> +	const u8 *method;
> +	struct opal_lock_unlock *lkul;
> +	int ret;
> +	u8 read_locked = 1, write_locked = 1;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	method = OPALMETHOD[OPAL_SET];
> +	lkul = dev->func_data[dev->state - 1];
> +	if (build_locking_range(lr_buffer, sizeof(lr_buffer), dev->lr) < 0) {
> +		pr_err("%s: Can't build locking range\n", dev->disk_name);
> +		return -EINVAL;
> +	}
> +
> +	switch (lkul->l_state) {
> +	case OPAL_RO:
> +		read_locked = 0;
> +		write_locked = 1;
> +		break;
> +	case OPAL_RW:
> +		read_locked = 0;
> +		write_locked = 0;
> +		break;
> +	case OPAL_LK:
> +		/* vars are initalized to locked */
> +		break;
> +	default:
> +		pr_err("Tried to set an invalid locking state... returning to uland\n");
> +		return 1;
> +	}
> +
> +	ret = test_and_add_token_va(cmd, "c2sc 3c 4c 4c 3c",
> +				    OPAL_CALL,
> +				    lr_buffer, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +				    OPAL_STARTLIST,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_VALUES,
> +				    OPAL_STARTLIST,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_READLOCKED,
> +				    read_locked,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_WRITELOCKED,
> +				    write_locked,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_ENDLIST,
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error building SET command.\n", dev->disk_name);
> +		return ret;
> +	}
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +
> +static int lock_unlock_locking_range_SUM(struct opal_dev *dev)
> +{
> +	u8 lr_buffer[OPAL_UID_LENGTH];
> +	struct opal_cmd *cmd;
> +	const u8 *method;
> +	struct opal_lock_unlock *lkul;
> +	int ret;
> +	u8 read_locked = 1, write_locked = 1;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	method = OPALMETHOD[OPAL_SET];
> +	lkul = dev->func_data[dev->state - 1];
> +	if (build_locking_range(lr_buffer, sizeof(lr_buffer), dev->lr) < 0) {
> +		pr_err("%s: Can't build locking range\n", dev->disk_name);
> +		return -EINVAL;
> +	}
> +
> +	switch (lkul->l_state) {
> +	case OPAL_RO:
> +		read_locked = 0;
> +		write_locked = 1;
> +		break;
> +	case OPAL_RW:
> +		read_locked = 0;
> +		write_locked = 0;
> +		break;
> +	case OPAL_LK:
> +		/* vars are initalized to locked */
> +		break;
> +	default:
> +		pr_err("Tried to set an invalid locking state.\n");
> +		return 1;
> +	}
> +
> +	ret = test_and_add_token_va(cmd, "c2sc 3c 4c 4c 4c 4c 3c",
> +				    OPAL_CALL,
> +				    lr_buffer, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +				    OPAL_STARTLIST,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_VALUES,
> +				    OPAL_STARTLIST,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_READLOCKENABLED,
> +				    OPAL_TRUE,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_WRITELOCKENABLED,
> +				    OPAL_TRUE,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_READLOCKED,
> +				    read_locked,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_WRITELOCKED,
> +				    write_locked,
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_ENDLIST,
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST);
> +	if (ret < 0) {
> +		pr_err("%s: Error building SET command.\n", dev->disk_name);
> +		return ret;
> +	}
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +int activate_lsp(struct opal_dev *dev)
> +{
> +	u8 user_lr[OPAL_UID_LENGTH];
> +	const u8 *method, *uid;
> +	struct opal_cmd *cmd;
> +	int ret;
> +	size_t uint_3 = 0x83;
> +
> +	cmd = &dev->cmd;
> +
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	uid = OPALUID[OPAL_LOCKINGSP_UID];
> +	method = OPALMETHOD[OPAL_ACTIVATE];
> +
> +	ret = test_and_add_token_va(cmd, "c2s",
> +				    OPAL_CALL,
> +				    uid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH);
> +	if (ret < 0) {
> +		pr_err("%s: Error building Activate LockingSP command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +	/* Activating as SUM */
> +	if (dev->lr > 0) {
> +		ret = build_locking_range(user_lr, sizeof(user_lr), dev->lr);
> +		if (ret < 0) {
> +			pr_err("%s: Can't build locking user\n",
> +			       dev->disk_name);
> +			return ret;
> +		}
> +		test_and_add_token_va(cmd, "2c 4c csc 2c",
> +				      OPAL_STARTLIST,
> +				      OPAL_STARTNAME,
> +
> +				      uint_3,
> +				      OPAL_TINY_UINT_06,
> +				      OPAL_TINY_UINT_00,
> +				      OPAL_TINY_UINT_00,
> +
> +				      OPAL_STARTLIST,
> +				      user_lr, OPAL_UID_LENGTH,
> +				      OPAL_ENDLIST,
> +
> +				      OPAL_ENDNAME,
> +				      OPAL_ENDLIST);
> +	} else /* Actiave Normal Mode */
> +		ret = test_and_add_token_va(cmd, "2c",
> +					    OPAL_STARTLIST,
> +					    OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error building Activate LockingSP command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, generic_cont);
> +}
> +
> +static void get_lsp_lifecycle_cont(int error, void *data)
> +{
> +
> +	struct opal_dev *dev = data;
> +	u8 lc_status;
> +
> +	if (error)
> +		goto err_return;
> +
> +	error = parse_and_check_status(dev);
> +	if (error)
> +		goto err_return;
> +
> +	lc_status = response_get_u64(&dev->parsed, 4);
> +	/* 0x08 is Manufacured Inactive */
> +	/* 0x09 is Manufactured */
> +	if (lc_status != 0x08) {
> +		pr_err("%s: Couldn't determine the status of the Lifcycle state\n",
> +		       dev->disk_name);
> +		error = -ENODEV;
> +	}
> +
> +err_return:
> +	if (dev->oper_cb)
> +		dev->oper_cb(error, dev);
> +}
> +
> +/* Determine if we're in the Manufactured Inactive or Active state */
> +int get_lsp_lifecycle(struct opal_dev *dev)
> +{
> +	struct opal_cmd *cmd;
> +	const u8 *method, *uid;
> +	int ret;
> +
> +	cmd = &dev->cmd;
> +
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	uid = OPALUID[OPAL_LOCKINGSP_UID];
> +	method = OPALMETHOD[OPAL_GET];
> +
> +	ret = test_and_add_token_va(cmd, "c2s 2c 4c 4c 2c",
> +				    OPAL_CALL,
> +				    uid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTLIST,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_03, /* Start Column */
> +				    OPAL_TINY_UINT_06, /* Lifcycle Column */
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_04, /* End Column */
> +				    OPAL_TINY_UINT_06, /* Lifecycle Column */
> +				    OPAL_ENDNAME,
> +
> +				    OPAL_ENDLIST,
> +				    OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error Building GET Lifecycle Status command\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, get_lsp_lifecycle_cont);
> +}
> +
> +static void get_msid_cpin_pin_cont(int error, void *data)
> +{
> +	const char *msid_pin;
> +	struct opal_dev *dev = data;
> +	size_t strlen;
> +
> +	if (error)
> +		goto err_return;
> +
> +	error = parse_and_check_status(dev);
> +	if (error)
> +		goto err_return;
> +
> +	strlen = response_get_string(&dev->parsed, 4, &msid_pin);
> +	if (!msid_pin) {
> +		pr_err("%s: Couldn't extract PIN from response\n", __func__);
> +		error = 1;
> +		goto err_return;
> +	}
> +
> +	dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
> +	if (!dev->prev_data)
> +		error = -ENOMEM;
> +
> +	dev->prev_d_len = strlen;
> +
> + err_return:
> +	if (dev->oper_cb)
> +		dev->oper_cb(error, dev);
> +}
> +
> +static int get_msid_cpin_pin(struct opal_dev *dev)
> +{
> +	const u8 *method, *smuid;
> +	int ret;
> +	struct opal_cmd *cmd;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +	set_comID(cmd, dev->comID);
> +
> +	smuid = OPALUID[OPAL_C_PIN_MSID];
> +	method = OPALMETHOD[OPAL_GET];
> +
> +	ret = test_and_add_token_va(cmd, "c 2s 12c",
> +				    OPAL_CALL,
> +
> +				    smuid, OPAL_UID_LENGTH,
> +				    method, OPAL_METHOD_LENGTH,
> +
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTLIST,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_03, /* Sart Column */
> +				    OPAL_TINY_UINT_03, /* PIN */
> +				    OPAL_ENDNAME,
> +				    OPAL_STARTNAME,
> +				    OPAL_TINY_UINT_04, /* End Column */
> +				    OPAL_TINY_UINT_03, /* PIN */
> +				    OPAL_ENDNAME,
> +				    OPAL_ENDLIST,
> +				    OPAL_ENDLIST);
> +
> +	if (ret < 0) {
> +		pr_err("%s: Error building Get MSID CPIN PIN command.\n",
> +		       dev->disk_name);
> +		return ret;
> +	}
> +
> +	return finalize_and_send(dev, cmd, get_msid_cpin_pin_cont);
> +}
> +
> +static void unlock_suspend_final(int error, void *data)
> +{
> +	struct opal_dev *dev = data;
> +
> +	dev->resume_from_suspend = false;
> +	dev->resume_data = NULL;
> +	dev->func_data = NULL;
> +	dev->bdev = NULL;
> +}
> +
> +static int build_end_opal_session(struct opal_dev *dev)
> +{
> +	struct opal_cmd *cmd;
> +
> +	cmd = &dev->cmd;
> +	clear_opal_cmd(cmd);
> +
> +	set_comID(cmd, dev->comID);
> +	return test_and_add_token_u8(cmd, OPAL_ENDOFSESSION);
> +}
> +
> +static int end_opal_session(struct opal_dev *dev)
> +{
> +	if (build_end_opal_session(dev) < 0)
> +		return -1;
> +	return finalize_and_send(dev, &dev->cmd, end_session_cont);
> +}
Any reason we cant:

int ret = build_...
if (ret < 0)
	return ret;


> +
> +static struct opal_dev *find_opal_dev(struct block_device *bdev, u8 lr)
> +{
> +	struct opal_dev *iter, *opal_dev = NULL;
> +
> +	list_for_each_entry(iter, &opal_list, node) {
> +		if (strncmp(iter->disk_name, bdev->bd_disk->disk_name,
> +			    DISK_NAME_LEN))
> +			continue;
> +		if (iter->lr == lr) {
> +			opal_dev = iter;
> +			break;
> +		}
> +	}
> +
> +	return opal_dev;
> +}
> +
> +static int update_opal_dev(struct opal_dev *old_dev, struct opal_dev *new_dev)
> +{
> +	if (!atomic_add_unless(&old_dev->in_use, 1, 1)) {
> +		pr_err("%s: dev was in use\n", __func__);
> +		return -EBUSY;
> +	}
> +
> +	old_dev->key_name_len = new_dev->key_name_len;
> +	if (!memcpy(old_dev->key_name, new_dev->key_name, old_dev->key_name_len)) {
> +		pr_err("%s: Error updating device:\n", old_dev->disk_name);
> +		return -EFAULT;
> +	}
> +
> +	if (!strncpy(old_dev->disk_name, new_dev->disk_name, DISK_NAME_LEN)) {
> +		pr_err("%s: Error registering device: copying disk name\n",
> +		       old_dev->disk_name);
> +		return -EFAULT;
> +	}
> +
> +	old_dev->comID = new_dev->comID;
> +	old_dev->start = new_dev->start;
> +	old_dev->length = new_dev->length;
> +	old_dev->align = new_dev->align;
> +	old_dev->lowest_lba = new_dev->lowest_lba;
> +	old_dev->bdev = NULL;
> +	old_dev->final_cb = new_dev->final_cb;
> +	old_dev->final_cb_data = new_dev->final_cb_data;
> +	old_dev->oper_cb = new_dev->oper_cb;
> +	old_dev->state = new_dev->state;
> +	old_dev->funcs = new_dev->funcs;
> +
> +	kfree(old_dev->completion);
> +	clean_function_data(old_dev);
> +
> +	old_dev->completion = new_dev->completion;
> +
> +	/*
> +	 * Won't be able to auto unlock this locking range based on block
> +	 * requestes.
> +	 */
> +	if (old_dev->length == 0)
> +		pr_warn("%s: Missing block information for locking range %d\n",
> +			old_dev->disk_name, old_dev->lr);
> +
> +	return 0;
> +}
> +
> +int opal_register_cont(struct opal_dev *new_dev)
> +{
> +	struct opal_dev *old_dev;
> +	unsigned long flags;
> +	int error = 0;
> +
> +	spin_lock_irqsave(&list_spinlock, flags);
> +
> +	old_dev = find_opal_dev(new_dev->bdev, new_dev->lr);
> +	if (!old_dev) {
> +		list_add_tail(&new_dev->node, &opal_list);
> +		old_dev = new_dev;
> +	} else {
> +		if (old_dev == new_dev)
> +			error = 0;
> +		else {
> +			error = update_opal_dev(old_dev, new_dev);
> +			clean_opal_key(new_dev);
> +			kfree(new_dev);
> +		}
> +	}
> +
> +	if (error)
> +		list_del(&old_dev->node);
> +
> +	spin_unlock_irqrestore(&list_spinlock, flags);
> +
> +	if (!error)
> +		pr_info("%s: Registered key for locking range: %d\n",
> +			old_dev->disk_name, old_dev->lr);
> +
> +	if (old_dev->oper_cb)
> +		old_dev->oper_cb(error, old_dev);
> +
> +	return 0;
> +}
> +
> +static void next(int error, struct opal_dev *dev)
> +{
> +	opal_step func = dev->funcs[dev->state];
> +	void *cb_data = dev->final_cb_data;
> +	sec_cb *cb = dev->final_cb;
> +	bool done = false;
> +
> +
> +	if (error || !func) {
> +		done = true;
> +		goto next_exit;
> +	}
> +	dev->state++;
> +	dev->oper_cb = next;
> +	error = func(dev);
> + next_exit:
> +	if (error) {
> +		pr_err("%s: Error on step function: %d with error %d: %s\n",
> +		       dev->disk_name, dev->state, error,
> +		       opal_error_to_human(error));
> +
> +
> +		atomic_dec(&dev->in_use);
> +		if (dev->error_cb) {
> +			dev->error_cb(dev->error_cb_data);
> +			return;
> +		}
> +		if (cb)
> +			cb(error, cb_data);
> +
> +		dev->completion->completion_status = error;
> +		complete(&dev->completion->cmd_completion);
> +	} else if (!error && done) {
> +		atomic_dec(&dev->in_use);
> +		if (cb)
> +			cb(error, cb_data);
> +		dev->completion->completion_status = error;
> +		complete(&dev->completion->cmd_completion);
> +	}
> +}
> +
> +const opal_step error_end_session[] = {
> +	end_opal_session,
> +	NULL,
> +};
> +static int end_opal_session_error(struct opal_dev *dev)
> +{
> +
> +	dev->funcs = error_end_session;
> +	dev->state = 0;
> +	dev->error_cb = NULL;
> +	next(0, dev);
> +	return 0;
> +}
> +
> +static struct opal_dev *alloc_opal_dev(struct block_device *bdev, u8 lr)
> +{
> +	struct opal_dev *opal_dev;
> +	struct request_queue *q;
> +	unsigned long dma_align;
> +	const char *disk_name;
> +	struct opal_cmd *cmd;
> +	int ret;
> +
> +	opal_dev = kzalloc(sizeof(*opal_dev), GFP_KERNEL);
> +	if (!opal_dev)
> +		return ERR_PTR(-ENOMEM);
> +
> +	opal_dev->bdev = bdev;
> +	opal_dev->lr = lr;
> +	cmd = &opal_dev->cmd;
> +	cmd->cmd = cmd->cmd_buf;
> +	cmd->resp = cmd->resp_buf;
> +
> +	disk_name = bdev->bd_disk->disk_name;
> +	if (!strncpy(opal_dev->disk_name, disk_name, DISK_NAME_LEN)) {
> +		pr_err("%s: Error registering device: copying disk name\n",
> +		       disk_name);
> +		ret = -EFAULT;
> +		goto err_free_dev;
> +	}
> +
> +	q = bdev->bd_queue;
> +	dma_align = (queue_dma_alignment(q) | q->dma_pad_mask) + 1;
> +	cmd->cmd = (u8 *)round_up((uintptr_t)cmd->cmd, dma_align);
> +	cmd->resp = (u8 *)round_up((uintptr_t)cmd->resp, dma_align);
> +
> +	INIT_LIST_HEAD(&opal_dev->node);
> +	atomic_set(&opal_dev->in_use, 1);
> +
> +	opal_dev->completion = kzalloc(sizeof(*opal_dev->completion),
> +				       GFP_KERNEL);
> +
> +	if (!opal_dev->completion)
> +		goto err_free_dev;
> +
> +	init_completion(&opal_dev->completion->cmd_completion);
> +	opal_dev->completion->completion_status = 0;
> +	opal_dev->state = 0;
> +
> +	return opal_dev;
> +
> +err_free_dev:
> +	kfree(opal_dev);
> +	return ERR_PTR(ret);
> +}
> +
> +int opal_register(struct block_device *bdev, struct opal_key *key_cmd,
> +		  const opal_step *funcs)
> +{
> +	struct opal_dev *new_dev = NULL;
> +	u8 key_len = key_cmd->key_len;
> +	u8 lr = key_cmd->lr;
> +	struct opal_completion *completion;
> +	int ret;
> +
> +	new_dev = alloc_opal_dev(bdev, lr);
> +	if (IS_ERR(new_dev)) {
> +		pr_err("%s: Error registering device: allocation\n",
> +		       bdev->bd_disk->disk_name);
> +		return PTR_ERR(new_dev);
> +	}
> +
> +	if (!memcpy(new_dev->key_name, key_cmd->key, key_len)) {
> +		pr_err("%s: Error registering key: couldn't copy key\n",
> +		       new_dev->disk_name);
> +		return -EFAULT;
> +	}
> +
> +	new_dev->key_name_len = key_len;
> +	new_dev->key_type = key_cmd->key_type;
> +	ret = get_opal_key(new_dev);
> +	if (ret) {
> +		pr_err("%s: Couldn't get key: %d\n", new_dev->disk_name, ret);
> +		return ret;
> +	}
> +
> +	new_dev->funcs = funcs;
> +
> +	new_dev->state = 0;
> +	completion = new_dev->completion;
> +	next(0, new_dev);
> +
> +	return wait_for_cmd_completion(completion);
> +}
> +
> +static struct opal_dev *get_registered_opal_dev(struct block_device *bdev,
> +						u8 lr)
> +{
> +	const char *diskname = bdev->bd_disk->disk_name;
> +	struct opal_dev *iter, *dev = NULL;
> +	unsigned long flags;
> +	bool in_use = false;
> +
> +	spin_lock_irqsave(&list_spinlock, flags);
> +	list_for_each_entry(iter, &opal_list, node) {
> +		if (strncmp(iter->disk_name, diskname, DISK_NAME_LEN))
> +			continue;
> +		if (iter->lr == lr) {
> +			dev = iter;
> +			if (!atomic_add_unless(&iter->in_use, 1, 1)) {
> +				dev = NULL;
> +				in_use = true;
> +			}
> +			break;
> +		}
> +	}
> +
> +	spin_unlock_irqrestore(&list_spinlock, flags);
> +
> +	if (!dev)
> +		return NULL;
> +
> +	dev->bdev = bdev;
> +	return dev;
> +}
> +
> +/* Free up the Opal dev and its keys during two scenarios:
> + *
> + * 1) When a command is complete that no longer requires
> + *    the opal dev to be around.
> + * 2) When a command, including Opal Save fails we clean
> + *    and free the opal dev.
> + *
> + *    If we find the opal dev structure in the list of
> + *    saved passwords we will *not* remove it.
> + */
> +static void remove_and_clean_opal_dev(struct opal_dev *dev)
> +{
> +	struct opal_dev *iter;
> +	bool found = false;
> +
> +	spin_lock(&list_spinlock);
> +	list_for_each_entry(iter, &opal_list, node) {
> +		if (iter == dev) {
> +			found = true;
> +			break;
> +		}
> +	}
> +
> +	spin_unlock(&list_spinlock);
> +	if (!found) {
> +		clean_opal_key(dev);
> +		clean_function_data(dev);
> +		kfree(dev);
> +	}
> +}
> +
> +static struct opal_dev *get_or_create_opal_dev(struct block_device *bdev,
> +					       u8 lr, bool use_new)
> +{
> +	struct opal_dev *dev;
> +
> +	if (use_new)
> +		return alloc_opal_dev(bdev, lr);
> +
> +	dev = get_registered_opal_dev(bdev, lr);
> +	if (!dev) {
> +		dev = alloc_opal_dev(bdev, lr);
> +		if (!dev)
> +			return NULL;
No need for this check when you already return dev


> +	}
> +	return dev;
> +}
Instead, how about:
static struct opal_dev *get_or_create_opal_dev(struct block_device *bdev,
					       u8 lr, bool use_new)
{
	struct opal_dev *dev = NULL;

	if (!use_new)
		dev = get_registered_opal_dev(bdev, lr);

	if (!dev)
		dev = alloc_opal_dev(bdev, lr);

	return dev;
}


> +
> +static struct opal_completion *setup_opal_dev(struct block_device *bdev,
> +					      struct opal_dev *dev,
> +					      const opal_step *funcs,
> +					      struct opal_key *key)
> +{
> +	int ret;
> +
> +	dev->bdev = bdev;
> +	dev->state = 0;
> +	dev->funcs = funcs;
> +	dev->TSN = 0;
> +	dev->HSN = 0;
> +	dev->final_cb = NULL;
> +	dev->final_cb_data = NULL;
> +	dev->lr = key->lr;
> +	dev->error_cb = end_opal_session_error;
> +	dev->error_cb_data = dev;
> +
> +	if (key) {
> +		memcpy(dev->key_name, key->key, key->key_len);
> +		dev->key_name_len = key->key_len;
> +		dev->key_type = key->key_type;
> +
> +		ret = get_opal_key(dev);
> +		if (ret) {
> +			kfree(dev->completion);
> +			pr_err("%s: Couldn't get key: %d\n",
> +			       dev->disk_name, ret);
> +			return ERR_PTR(ret);
> +		}
> +	}
> +	dev->func_data = NULL;
> +	dev->completion->completion_status = 0;
> +
> +	return dev->completion;
> +}
> +
> +static int internal_setup_lr(struct block_device *bdev,
> +			     struct opal_user_lr_setup *setup)
> +{
> +	struct opal_dev *dev;
> +	struct opal_completion *completion;
> +	void *data[3] = { NULL };
> +	const opal_step lr_funcs[] = {
> +		opal_discovery0,
> +		start_auth_opal_session,
> +		setup_locking_range,
> +		get_active_key,
> +		gen_key,
> +		end_opal_session,
> +		NULL,
> +	};
> +	int ret;
> +
> +	dev = get_or_create_opal_dev(bdev, setup->key.lr, true);
> +	if (!dev)
> +		return -ENOMEM;
> +
> +	completion = setup_opal_dev(bdev, dev, lr_funcs, &setup->key);
> +	if (IS_ERR(completion)) {
> +		ret = PTR_ERR(completion);
> +		goto error_return;
> +	}
> +
> +	dev->func_data = data;
> +	dev->num_func_data = 3;
> +	dev->func_data[1] = &setup->who;
> +	dev->func_data[2] = setup;
> +
> +	next(0, dev);
> +	ret = wait_for_cmd_completion(completion);
> +
> + error_return:
> +	remove_and_clean_opal_dev(dev);
> +	return ret;
> +}
> +
> +int opal_revert(struct block_device *bdev, struct opal_key *key)
> +{
> +	const opal_step revert_funcs[] = {
> +		opal_discovery0,
> +		start_SIDASP_opal_session,
> +		revert_tper, /* controller will terminate session */
> +		NULL,
> +	};
> +
> +	return opal_register(bdev, key, revert_funcs);
> +}
> +
> +int activate_user(struct block_device *bdev, struct opal_activate_user *act)
> +{
> +	const opal_step act_funcs[] = {
> +		opal_discovery0,
> +		start_admin1LSP_opal_session,
> +		internal_activate_user,
> +		end_opal_session,
> +		NULL
> +	};
> +	struct opal_dev *dev;
> +	struct opal_completion *completion;
> +	void *data[3] = { NULL };
> +	int ret;
> +
> +	dev = get_or_create_opal_dev(bdev, act->key.lr, true);
> +	if (!dev)
> +		return -ENOMEM;
> +
> +	completion = setup_opal_dev(bdev, dev, act_funcs, &act->key);
> +	if (IS_ERR(completion)) {
> +		ret = PTR_ERR(completion);
> +		goto error_return;
> +	}
> +
> +	dev->num_func_data = 3;
> +	dev->func_data = data;
> +	dev->func_data[1] = act;
> +	dev->func_data[2] = act;
> +
> +	next(0, dev);
> +	ret = wait_for_cmd_completion(completion);
> +
> + error_return:
> +	remove_and_clean_opal_dev(dev);
> +	return ret;
> +}
> +
> +int opal_set_pw(struct block_device *bdev, struct opal_new_pw *pw)
> +
> +{
> +	const opal_step pw_funcs[] = {
> +		opal_discovery0,
> +		start_auth_opal_session,
> +		set_new_pw,
> +		end_opal_session,
> +		NULL
> +	};
> +	struct opal_dev *dev;
> +	struct opal_completion *completion;
> +	void *data[3] = { NULL };
> +	int ret;
> +
> +	dev = get_or_create_opal_dev(bdev, pw->current_pin.lr, true);
> +	if (!dev)
> +		return -ENOMEM;
> +
> +	completion = setup_opal_dev(bdev, dev, pw_funcs, &pw->current_pin);
> +	if (IS_ERR(completion)) {
> +		ret = PTR_ERR(completion);
> +		goto error_return;
> +	}
> +
> +	dev->num_func_data = 3;
> +	dev->func_data = data;
> +	dev->func_data[1] = (void *) &pw->who;
> +	dev->func_data[2] = (void *) pw;
> +
> +	next(0, dev);
> +	ret = wait_for_cmd_completion(completion);
> +
> + error_return:
> +	remove_and_clean_opal_dev(dev);
> +	return ret;
> +}
> +
> +int opal_act_lsp_int(struct block_device *bdev, struct opal_key *key,
> +		     const opal_step *funcs)
> +{
> +	struct opal_dev *dev;
> +	struct opal_completion *completion;
> +	int ret;
> +
> +	dev = get_or_create_opal_dev(bdev, key->lr, true);
> +	if (!dev)
> +		return -ENOMEM;
> +	completion = setup_opal_dev(bdev, dev, funcs, key);
> +	if (IS_ERR(completion)) {
> +		ret = PTR_ERR(completion);
> +		goto error_return;
> +	}
> +
> +	next(0, dev);
> +	ret = wait_for_cmd_completion(completion);
> +
> + error_return:
> +	remove_and_clean_opal_dev(dev);
> +	return ret;
> +}
> +
> +
> +static int opal_save_internal(struct block_device *bdev,
> +			      struct opal_lock_unlock *lk)
> +{
> +	void *func_data[3] = { NULL };
> +	struct opal_dev *dev;
> +	struct opal_completion *completion;
> +	const opal_step _auth_funcs[] = {
> +		opal_discovery0,
> +		start_auth_opal_session,
> +		query_locking_range,
> +		end_opal_session,
> +		opal_register_cont,
> +		NULL
> +	};
> +	int ret;
> +
> +	dev = get_or_create_opal_dev(bdev, lk->key.lr, false);
> +	if (!dev)
> +		return -ENOMEM;
> +	completion = setup_opal_dev(bdev, dev, _auth_funcs, &lk->key);
> +	if (IS_ERR(completion)) {
> +		ret = PTR_ERR(completion);
> +		goto error_return;
> +	}
> +
> +	dev->num_func_data = 3;
> +	dev->func_data = func_data;
> +	dev->func_data[1] = &lk->authority;
> +	dev->lkul = *lk;
> +
> +	next(0, dev);
> +	ret = wait_for_cmd_completion(completion);
> +
> + error_return:
> +	remove_and_clean_opal_dev(dev);
> +	return ret;
> +}
> +
> +static int add_user_lr_internal(struct block_device *bdev,
> +				struct opal_lock_unlock *lk)
> +{
> +	void *func_data[3] = { NULL };
> +	struct opal_dev *dev;
> +	struct opal_completion *completion;
> +	const opal_step funcs[] = {
> +		opal_discovery0,
> +		start_admin1LSP_opal_session,
> +		add_user_to_lr,
> +		end_opal_session,
> +		NULL
> +	};
> +	int ret;
> +
> +	dev = get_or_create_opal_dev(bdev, lk->key.lr, true);
> +	if (!dev)
> +		return -ENOMEM;
> +	completion = setup_opal_dev(bdev, dev, funcs, &lk->key);
> +	if (IS_ERR(completion)) {
> +		ret = PTR_ERR(completion);
> +		goto error_return;
> +	}
> +
> +	dev->num_func_data = 3;
> +	dev->func_data = func_data;
> +	dev->func_data[2] = lk;
> +
> +	next(0, dev);
> +	ret = wait_for_cmd_completion(completion);
> +
> + error_return:
> +	remove_and_clean_opal_dev(dev);
> +	return ret;
> +}
> +
> +static int lock_unlock_internal(struct block_device *bdev,
> +				struct opal_lock_unlock *lk)
> +{
> +	void *func_data[3] = { NULL };
> +	struct opal_dev *dev;
> +	struct opal_completion *completion;
> +
> +	const opal_step ulk_funcs_SUM[] = {
> +		opal_discovery0,
> +		start_auth_opal_session,
> +		lock_unlock_locking_range_SUM,
> +		end_opal_session,
> +		NULL
> +	};
> +	const opal_step _unlock_funcs[] = {
> +		opal_discovery0,
> +		start_auth_opal_session,
> +		lock_unlock_locking_range,
> +		end_opal_session,
> +		NULL
> +	};
> +	int ret;
> +
> +	dev = get_or_create_opal_dev(bdev, lk->key.lr, true);
> +	if (!dev)
> +		return -ENOMEM;
> +
> +	if (lk->authority.SUM)
> +		completion = setup_opal_dev(bdev, dev, ulk_funcs_SUM, &lk->key);
> +	else
> +		completion = setup_opal_dev(bdev, dev, _unlock_funcs, &lk->key);
> +
> +	if (IS_ERR(completion)) {
> +		ret = PTR_ERR(completion);
> +		goto error_return;
> +	}
> +
> +	dev->num_func_data = 3;
> +	dev->func_data = func_data;
> +	dev->func_data[1] = &lk->authority;
> +	dev->func_data[2] = lk;
> +
> +	next(0, dev);
> +	ret = wait_for_cmd_completion(completion);
> +
> + error_return:
> +	remove_and_clean_opal_dev(dev);
> +	return ret;
> +}
> +
> +int opal_erase_locking_range(struct block_device *bdev, struct sed_key *key)
> +{
> +	struct opal_dev *dev;
> +	struct opal_completion *completion;
> +	struct opal_key k;
> +	int ret;
> +	const opal_step erase_funcs[] = {
> +		opal_discovery0,
> +		start_admin1LSP_opal_session,
> +		erase_locking_range,
> +		end_opal_session,
> +		NULL,
> +	};
> +
> +	if (!bdev || !bdev->bd_disk) {
> +		pr_err("Can't save password for NULL block device.\n");
> +		return -EINVAL;
> +	}
> +
> +	if (copy_from_user(&k, key->opal, sizeof(*key->opal)))
> +		return -EFAULT;
> +
> +	dev = get_or_create_opal_dev(bdev, k.lr, true);
> +	if (!dev)
> +		return -ENOMEM;
> +
> +	completion = setup_opal_dev(bdev, dev, erase_funcs, &k);
> +	if (IS_ERR(completion)) {
> +		ret = PTR_ERR(completion);
> +		goto error_return;
> +	}
> +
> +	next(0, dev);
> +	ret = wait_for_cmd_completion(completion);
> +
> + error_return:
> +	remove_and_clean_opal_dev(dev);
> +	return ret;
> +}
> +EXPORT_SYMBOL(opal_erase_locking_range);
> +
> +int opal_enable_disable_shadow_mbr(struct block_device *bdev,
> +				   struct sed_key *key)
> +{
> +	void *func_data[6] = { NULL };
> +	struct opal_mbr_data mbr;
> +	struct opal_dev *dev;
> +	struct opal_completion *completion;
> +	const opal_step mbr_funcs[] = {
> +		opal_discovery0,
> +		start_admin1LSP_opal_session,
> +		set_mbr_done,
> +		end_opal_session,
> +		start_admin1LSP_opal_session,
> +		set_mbr_enable_disable,
> +		end_opal_session,
> +		NULL,
> +	};
> +	int ret;
> +
> +	if (!bdev || !bdev->bd_disk) {
> +		pr_err("Can't save password for NULL block device.\n");
> +		return -EINVAL;
> +	}
> +
> +	if (copy_from_user(&mbr, key->opal_mbr, sizeof(*key->opal_mbr)))
> +		return -EFAULT;
> +
> +	if (mbr.enable_disable != OPAL_MBR_ENABLE &&
> +	    mbr.enable_disable != OPAL_MBR_DISABLE)
> +		return -EINVAL;
> +
> +	dev = get_or_create_opal_dev(bdev, mbr.key.lr, true);
> +	if (!dev)
> +		return -ENOMEM;
> +
> +	completion = setup_opal_dev(bdev, dev, mbr_funcs, &mbr.key);
> +	if (IS_ERR(completion)) {
> +		ret = PTR_ERR(completion);
> +		goto error_return;
> +	}
> +
> +	dev->num_func_data = 6;
> +	dev->func_data = func_data;
> +	dev->func_data[2] = &mbr.enable_disable;
> +	dev->func_data[5] = &mbr.enable_disable;
> +
> +	next(0, dev);
> +	ret = wait_for_cmd_completion(completion);
> +
> + error_return:
> +	remove_and_clean_opal_dev(dev);
> +	return ret;
> +
> +}
> +EXPORT_SYMBOL(opal_enable_disable_shadow_mbr);
> +
> +int opal_save(struct block_device *bdev, struct sed_key *key)
> +{
> +	struct opal_lock_unlock lkul;
> +
> +	if (!bdev || !bdev->bd_disk) {
> +		pr_err("Can't save password for NULL block device.\n");
> +		return -EINVAL;
> +	}
> +
> +	if (copy_from_user(&lkul, key->opal_lk_unlk, sizeof(*key->opal)))
> +		return -EFAULT;
> +
> +	return opal_save_internal(bdev, &lkul);
> +}
> +EXPORT_SYMBOL(opal_save);
> +
> +int opal_add_user_to_lr(struct block_device *bdev, struct sed_key *key)
> +{
> +	struct opal_lock_unlock lkul;
> +
> +	if (copy_from_user(&lkul, key->opal_lk_unlk, sizeof(lkul)))
> +		return -EFAULT;
> +
> +	if (!bdev || !bdev->bd_disk) {
> +		pr_err("Can't assign user to LR without backing disk\n");
> +		return -EFAULT;
> +	}
> +	if (lkul.l_state != OPAL_RO && lkul.l_state != OPAL_RW) {
> +		pr_err("Locking state was not RO or RW\n");
> +		return -EINVAL;
> +	}
> +	if (lkul.authority.who < OPAL_USER1 &&
> +	    lkul.authority.who > OPAL_USER9) {
> +		pr_err("Authority was not within the range of users: %d\n",
> +		       lkul.authority.who);
> +		return -EINVAL;
> +	}
> +	if (lkul.authority.SUM) {
> +		pr_err("%s not supported in SUM. Use setup locking range\n",
> +		       __func__);
> +		return -EINVAL;
> +	}
> +
> +	return add_user_lr_internal(bdev, &lkul);
> +}
> +EXPORT_SYMBOL(opal_add_user_to_lr);
> +
> +int opal_reverttper(struct block_device *bdev, struct sed_key *key)
> +{
> +	struct opal_key k;
> +
> +	if (copy_from_user(&k, key->opal, sizeof(*key->opal)))
> +		return -EFAULT;
> +
> +	return opal_revert(bdev, &k);
> +}
> +EXPORT_SYMBOL(opal_reverttper);
> +
> +int opal_lock_unlock(struct block_device *bdev, struct sed_key *key)
> +{
> +	struct opal_lock_unlock k;
> +
> +	if (copy_from_user(&k, key->opal_lk_unlk, sizeof(*key->opal_lk_unlk)))
> +		return -EFAULT;
> +
> +	if (k.authority.who < OPAL_ADMIN1 || k.authority.who >= OPAL_USER9)
Should this be > OPAL_USER9 ?


> +		return -EINVAL;
> +
> +	return lock_unlock_internal(bdev, &k);
> +}
> +EXPORT_SYMBOL(opal_lock_unlock);
> +
> +int opal_take_ownership(struct block_device *bdev, struct sed_key *key)
> +{
> +	struct opal_key k;
> +	const opal_step owner_funcs[] = {
> +		opal_discovery0,
> +		start_anybodyASP_opal_session,
> +		get_msid_cpin_pin,
> +		end_opal_session,
> +		start_SIDASP_opal_session,
> +		set_sid_cpin_pin,
> +		end_opal_session,
> +		NULL
> +	};
> +
> +	if (!bdev || !bdev->bd_disk) {
> +		pr_err("Can't save password for NULL block device.\n");
> +		return -EINVAL;
> +	}
> +
> +	if (copy_from_user(&k, key->opal, sizeof(*key->opal)))
> +		return -EFAULT;
> +
> +	return opal_register(bdev, &k, owner_funcs);
> +}
> +EXPORT_SYMBOL(opal_take_ownership);
> +
> +int opal_activate_lsp(struct block_device *bdev, struct sed_key *key)
> +{
> +	struct opal_key k;
> +	const opal_step active_funcs[] = {
> +		opal_discovery0,
> +		start_SIDASP_opal_session, /* Open session as SID auth */
> +		get_lsp_lifecycle,
> +		activate_lsp,
> +		end_opal_session,
> +		NULL
> +	};
> +
> +	if (!bdev || !bdev->bd_disk) {
> +		pr_err("Can't save password for NULL block device.\n");
> +		return -EINVAL;
> +	}
> +
> +	if (copy_from_user(&k, key->opal, sizeof(*key->opal)))
> +		return -EFAULT;
> +
> +	return opal_act_lsp_int(bdev, &k, active_funcs);
> +}
> +EXPORT_SYMBOL(opal_activate_lsp);
> +
> +int opal_setup_locking_range(struct block_device *bdev, struct sed_key *pw)
> +{
> +	struct opal_user_lr_setup k;
> +
> +	if (!bdev || !bdev->bd_disk) {
> +		pr_err("Can't save password for NULL block device.\n");
> +		return -EINVAL;
> +	}
> +
> +	if (copy_from_user(&k, pw->opal_lrs, sizeof(*pw->opal_lrs)))
> +		return -EFAULT;
> +
> +	return internal_setup_lr(bdev, &k);
> +}
> +
> +int opal_set_new_pw(struct block_device *bdev, struct sed_key *pw)
> +{
> +	struct opal_new_pw k;
> +
> +	if (pw->sed_type != OPAL_PW)
> +		return -EINVAL;
> +
> +	if (copy_from_user(&k, pw->opal_pw, sizeof(*pw->opal_pw)))
> +		return -EFAULT;
> +
> +	if (k.who.who < OPAL_ADMIN1 || k.who.who > OPAL_USER9)
> +		return -EINVAL;
> +
> +	return opal_set_pw(bdev, &k);
> +}
> +EXPORT_SYMBOL(opal_set_new_pw);
> +
> +int opal_activate_user(struct block_device *bdev, struct sed_key *pw)
> +{
> +	struct opal_activate_user k;
> +
> +	if (pw->sed_type != OPAL_ACT_USR) {
> +		pr_err("Sed type was not act user\n");
> +		return -EINVAL;
> +	}
> +
> +	if (copy_from_user(&k, pw->opal_act, sizeof(*pw->opal_act))) {
> +		pr_err("copy from user error\n");
> +		return -EFAULT;
> +	}
> +
> +	/* We can't activate Admin1 it's active as manufactured */
> +	if (k.who.who < OPAL_USER1 && k.who.who > OPAL_USER9) {
> +		pr_err("Who was not a valid user: %d \n", k.who.who);
> +		return -EINVAL;
> +	}
> +
> +	return activate_user(bdev, &k);
> +
> +}
> +EXPORT_SYMBOL(opal_activate_user);
> +
> +int opal_unlock_from_suspend(struct opal_suspend_unlk *data)
> +{
> +	const char *diskname = data->name;
> +	struct opal_dev *iter, *dev = NULL;
> +	struct opal_completion *completion;
> +	void *func_data[3] = { NULL };
> +	const opal_step _unlock_funcs_SUM[] = {
> +		opal_discovery0,
> +		start_auth_opal_session,
> +		lock_unlock_locking_range,
Did you mean to use lock_unlock_locking_range_SUM ?
Can we pull these two arrays out since they are required for both this
function and lock_unlock_internal ?


> +		end_opal_session,
> +		NULL
> +	};
> +	const opal_step _unlock_funcs[] = {
> +		opal_discovery0,
> +		start_auth_opal_session,
> +		lock_unlock_locking_range,
> +		end_opal_session,
> +		NULL
> +	};
> +
> +
> +	spin_lock(&list_spinlock);
> +	list_for_each_entry(iter, &opal_list, node) {
> +		if (strncmp(iter->disk_name, diskname, DISK_NAME_LEN)) {
> +			pr_err("iterdisk was %s and diskname is %s\n",
> +			       iter->disk_name, diskname);
> +			continue;
> +		}
> +		if (atomic_add_unless(&iter->in_use, 1, 1)) {
> +			dev = iter;
> +			dev->func_data = func_data;
> +			dev->resume_from_suspend = true;
> +			dev->resume_data = data;
> +			dev->final_cb = unlock_suspend_final;
> +			dev->final_cb_data = dev;
> +			dev->error_cb = end_opal_session_error;
> +			dev->error_cb_data = dev;
> +			dev->state = 0;
> +			if (dev->lkul.authority.SUM)
> +				dev->funcs = _unlock_funcs_SUM;
> +			else
> +				dev->funcs = _unlock_funcs;
> +			dev->TSN = 0;
> +			dev->HSN = 0;
> +			dev->func_data[2] = &dev->lkul;
> +			dev->func_data[1] = &dev->lkul.authority;
> +			completion = dev->completion;
> +			next(0, dev);
> +			wait_for_cmd_completion(completion);
> +		}
> +	}
> +	spin_unlock(&list_spinlock);
> +
> +	if (!dev)
> +		return -ENODEV;
> +	return 0;
> +}
> +EXPORT_SYMBOL(opal_unlock_from_suspend);
> diff --git a/lib/sed-opal_internal.h b/lib/sed-opal_internal.h
> new file mode 100644
> index 0000000..c9d3883
> --- /dev/null
> +++ b/lib/sed-opal_internal.h
> @@ -0,0 +1,586 @@
> +/*
> + * Copyright ? 2016 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Author:
> + *    Rafael Antognolli <rafael.antognolli at intel.com>
> + *    Scott  Bauer      <scott.bauer at intel.com>
> + */
> +
> +#ifndef _NVME_OPAL_INTERNAL_H
> +#define _NVME_OPAL_INTERNAL_H
> +
> +#include <linux/key-type.h>
> +#include <keys/user-type.h>
> +
> +#define DTAERROR_NO_METHOD_STATUS 0x89
> +
> +static const char *opal_errors[19] = {
Remove the 19 so it's just opal_errors[] (doesnt silently truncate any
new additions)


> +	"Success",
> +	"Not Authorized",
> +	"Unknown Error",
> +	"SP Busy",
> +	"SP Failed",
> +	"SP Disabled",
> +	"SP Frozen",
> +	"No Sessions Available",
> +	"Uniqueness Conflict",
> +	"Insufficient Space",
> +	"Insufficient Rows",
> +	"Invalid Function",
> +	"Invalid Parameter",
> +	"Invalid Reference",
> +	"Unknown Error",
> +	"TPER Malfunction",
> +	"Transaction Failure",
> +	"Response Overflow",
> +	"Authority Locked Out",
> +};
> +
> +static const char *opal_error_to_human(int error)
> +{
> +	if (error == 0x3f)
> +		return "Failed";
> +
> +	if (error >= sizeof(opal_errors) || error < 0)
You want sizeof(opal_errors)/sizeof(*opal_errors) here, but you can just
use the ARRAY_SIZE macro instead


> +		return "Unknown Error";
> +
> +	return opal_errors[error];
> +}
> +
> +/* User IDs used in the TCG storage SSCs */
> +static const u8 OPALUID[][8] = {
> +	/* users */
> +
> +	/* session management  */
> +	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},
> +	/* special "thisSP" syntax */
> +	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
> +	/* Administrative SP */
> +	{ 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 },
> +	/* Locking SP */
> +	{ 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 },
> +	/* ENTERPRISE Locking SP  */
> +	{ 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 },
> +	/* anybody */
> +	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 },
> +	/* SID */
> +	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 },
> +	/* ADMIN1 */
> +	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 },
> +	/* USER1 */
> +	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 },
> +	/* USER2 */
> +	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 },
> +	/* PSID user */
> +	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 },
> +	/* BandMaster 0 */
> +	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 },
> +	 /* EraseMaster */
> +	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 },
> +
> +	/* tables */
> +
> +	/* Locking_GlobalRange */
> +	{ 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
> +	/* ACE_Locking_Range_Set_RdLocked UID */
> +	{ 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
> +	/* ACE_Locking_Range_Set_WrLocked UID */
> +	{ 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
> +	/* MBR Control */
> +	{ 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
> +	/* Shadow MBR */
> +	{ 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
> +	/* AUTHORITY_TABLE */
> +	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
> +	/* C_PIN_TABLE */
> +	{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
> +	/* OPAL Locking Info */
> +	{ 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
> +	/* Enterprise Locking Info */
> +	{ 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
> +
> +	/* C_PIN_TABLE object ID's */
> +
> +	/* C_PIN_MSID */
> +	{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02},
> +	/* C_PIN_SID */
> +	{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01},
> +	 /* C_PIN_ADMIN1 */
> +	{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01},
> +
> +	/* half UID's (only first 4 bytes used) */
> +
> +	/* Half-UID ? Authority_object_ref */
> +	{ 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
> +	/* Half-UID ? Boolean ACE */
> +	{ 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
> +
> +	/* special value for omitted optional parameter */
> +
> +	/* HEXFF for omitted */
> +	{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
> +};
> +static const size_t OPAL_UID_LENGTH = 8;
> +static const size_t OPAL_MSID_KEYLEN = 15;
> +static const size_t OPAL_UID_LENGTH_HALF = 4;
> +
> +
> +/* Enum to index OPALUID array */
> +enum OPAL_UID {
> +	/* users */
> +	OPAL_SMUID_UID,
> +	OPAL_THISSP_UID,
> +	OPAL_ADMINSP_UID,
> +	OPAL_LOCKINGSP_UID,
> +	OPAL_ENTERPRISE_LOCKINGSP_UID,
> +	OPAL_ANYBODY_UID,
> +	OPAL_SID_UID,
> +	OPAL_ADMIN1_UID,
> +	OPAL_USER1_UID,
> +	OPAL_USER2_UID,
> +	OPAL_PSID_UID,
> +	OPAL_ENTERPRISE_BANDMASTER0_UID,
> +	OPAL_ENTERPRISE_ERASEMASTER_UID,
> +	/* tables */
> +	OPAL_LOCKINGRANGE_GLOBAL,
> +	OPAL_LOCKINGRANGE_ACE_RDLOCKED,
> +	OPAL_LOCKINGRANGE_ACE_WRLOCKED,
> +	OPAL_MBRCONTROL,
> +	OPAL_MBR,
> +	OPAL_AUTHORITY_TABLE,
> +	OPAL_C_PIN_TABLE,
> +	OPAL_LOCKING_INFO_TABLE,
> +	OPAL_ENTERPRISE_LOCKING_INFO_TABLE,
> +	/* C_PIN_TABLE object ID's */
> +	OPAL_C_PIN_MSID,
> +	OPAL_C_PIN_SID,
> +	OPAL_C_PIN_ADMIN1,
> +	/* half UID's (only first 4 bytes used) */
> +	OPAL_HALF_UID_AUTHORITY_OBJ_REF,
> +	OPAL_HALF_UID_BOOLEAN_ACE,
> +	/* omitted optional parameter */
> +	OPAL_UID_HEXFF,
> +};
> +
> +/*
> + * TCG Storage SSC Methods.
> + */
> +static const u8 OPALMETHOD[][8] = {
> +	/* Properties */
> +	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
> +	/* STARTSESSION */
> +	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
> +	/* Revert */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
> +	/* Activate */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
> +	/* Enterprise Get */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
> +	/* Enterprise Set */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
> +	/* NEXT */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
> +	/* Enterprise Authenticate */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
> +	/* GetACL */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
> +	/* GenKey */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
> +	/* revertSP */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
> +	/* Get */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
> +	/* Set */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
> +	/* Authenticate */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
> +	/* Random */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
> +	/* Erase */
> +	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
> +};
> +static const size_t OPAL_METHOD_LENGTH = 8;
> +
> +/* Enum for indexing the OPALMETHOD array */
> +enum OPAL_METHOD {
> +	OPAL_PROPERTIES,
> +	OPAL_STARTSESSION,
> +	OPAL_REVERT,
> +	OPAL_ACTIVATE,
> +	OPAL_EGET,
> +	OPAL_ESET,
> +	OPAL_NEXT,
> +	OPAL_EAUTHENTICATE,
> +	OPAL_GETACL,
> +	OPAL_GENKEY,
> +	OPAL_REVERTSP,
> +	OPAL_GET,
> +	OPAL_SET,
> +	OPAL_AUTHENTICATE,
> +	OPAL_RANDOM,
> +	OPAL_ERASE,
> +};
> +
> +enum OPAL_RESPONSE_TOKEN {
> +	OPAL_DTA_TOKENID_BYTESTRING = 0xe0,
> +	OPAL_DTA_TOKENID_SINT = 0xe1,
> +	OPAL_DTA_TOKENID_UINT = 0xe2,
> +	OPAL_DTA_TOKENID_TOKEN = 0xe3, /* actual token is returned */
> +	OPAL_DTA_TOKENID_INVALID = 0X0
> +};
> +
> +enum OPAL_TOKEN {
> +	/* Boolean */
> +	OPAL_TRUE = 0x01,
> +	OPAL_FALSE = 0x00,
> +	OPAL_BOOLEAN_EXPR = 0x03,
> +	/* cellblocks */
> +	OPAL_TABLE = 0x00,
> +	OPAL_STARTROW = 0x01,
> +	OPAL_ENDROW = 0x02,
> +	OPAL_STARTCOLUMN = 0x03,
> +	OPAL_ENDCOLUMN = 0x04,
> +	OPAL_VALUES = 0x01,
> +	/* authority table */
> +	OPAL_PIN = 0x03,
> +	/* locking tokens */
> +	OPAL_RANGESTART = 0x03,
> +	OPAL_RANGELENGTH = 0x04,
> +	OPAL_READLOCKENABLED = 0x05,
> +	OPAL_WRITELOCKENABLED = 0x06,
> +	OPAL_READLOCKED = 0x07,
> +	OPAL_WRITELOCKED = 0x08,
> +	OPAL_ACTIVEKEY = 0x0A,
> +	/* locking info table */
> +	OPAL_MAXRANGES = 0x04,
> +	 /* mbr control */
> +	OPAL_MBRENABLE = 0x01,
> +	OPAL_MBRDONE = 0x02,
> +	/* properties */
> +	OPAL_HOSTPROPERTIES = 0x00,
> +	/* atoms */
> +	OPAL_STARTLIST = 0xf0,
> +	OPAL_ENDLIST = 0xf1,
> +	OPAL_STARTNAME = 0xf2,
> +	OPAL_ENDNAME = 0xf3,
> +	OPAL_CALL = 0xf8,
> +	OPAL_ENDOFDATA = 0xf9,
> +	OPAL_ENDOFSESSION = 0xfa,
> +	OPAL_STARTTRANSACTON = 0xfb,
> +	OPAL_ENDTRANSACTON = 0xfC,
> +	OPAL_EMPTYATOM = 0xff,
> +	OPAL_WHERE = 0x00,
> +};
> +
> +/* Useful tiny atoms.
> + * Useful for table columns etc
> + */
> +enum OPAL_TINY_ATOM {
> +	OPAL_TINY_UINT_00 = 0x00,
> +	OPAL_TINY_UINT_01 = 0x01,
> +	OPAL_TINY_UINT_02 = 0x02,
> +	OPAL_TINY_UINT_03 = 0x03,
> +	OPAL_TINY_UINT_04 = 0x04,
> +	OPAL_TINY_UINT_05 = 0x05,
> +	OPAL_TINY_UINT_06 = 0x06,
> +	OPAL_TINY_UINT_07 = 0x07,
> +	OPAL_TINY_UINT_08 = 0x08,
> +	OPAL_TINY_UINT_09 = 0x09,
> +	OPAL_TINY_UINT_10 = 0x0a,
> +	OPAL_TINY_UINT_11 = 0x0b,
> +	OPAL_TINY_UINT_12 = 0x0c,
> +	OPAL_TINY_UINT_13 = 0x0d,
> +	OPAL_TINY_UINT_14 = 0x0e,
> +	OPAL_TINY_UINT_15 = 0x0f,
> +};
> +
> +enum OPAL_ATOM_WIDTH {
> +	OPAL_WIDTH_TINY,
> +	OPAL_WIDTH_SHORT,
> +	OPAL_WIDTH_MEDIUM,
> +	OPAL_WIDTH_LONG,
> +	OPAL_WIDTH_TOKEN
> +};
> +
> +/* Locking state for a locking range */
> +enum OPAL_LOCKINGSTATE {
> +	OPAL_LOCKING_READWRITE = 0x01,
> +	OPAL_LOCKING_READONLY = 0x02,
> +	OPAL_LOCKING_LOCKED = 0x03,
> +};
> +
> +/*
> + * Structures to build and decode the Opal SSC messages
> + * fields that are NOT really numeric are defined as u8[] to
> + * help reduce the endianness issues
> + */
> +
> +/* Comm Packet (header) for transmissions. */
> +struct opal_compacket {
> +	u32 reserved0;
> +	u8 extendedComID[4];
> +	u32 outstandingData;
> +	u32 minTransfer;
> +	u32 length;
> +};
> +
> +/* Packet structure. */
> +struct opal_packet {
> +	u32 TSN;
> +	u32 HSN;
> +	u32 seq_number;
> +	u16 reserved0;
> +	u16 ack_type;
> +	u32 acknowledgment;
> +	u32 length;
> +};
> +
> +/* Data sub packet header */
> +struct opal_data_subpacket {
> +	u8 reserved0[6];
> +	u16 kind;
> +	u32 length;
> +};
> +
> +/* header of a response */
> +struct opal_header {
> +	struct opal_compacket cp;
> +	struct opal_packet pkt;
> +	struct opal_data_subpacket subpkt;
> +};
> +
> +#define FC_TPER       0x0001
> +#define FC_LOCKING    0x0002
> +#define FC_GEOMETRY   0x0003
> +#define FC_ENTERPRISE 0x0100
> +#define FC_DATASTORE  0x0202
> +#define FC_SINGLEUSER 0x0201
> +#define FC_OPALV100   0x0200
> +#define FC_OPALV200   0x0203
> +
> +/*
> + * The Discovery 0 Header. As defined in
> + * Opal SSC Documentation
> + */
> +struct d0_header {
> +	u32 length; /* the length of the header 48 in 2.00.100 */
> +	u32 revision; /**< revision of the header 1 in 2.00.100 */
> +	u32 reserved01;
> +	u32 reserved02;
> +	/*
> +	 * the remainder of the structure is vendor specific and will not be
> +	 * addressed now
> +	 */
> +	u8 ignored[32];
> +};
> +
> +/*
> + * TPer Feature Descriptor. Contains flags indicating support for the
> + * TPer features described in the OPAL specification. The names match the
> + * OPAL terminology
> + *
> + * code == 0x001 in 2.00.100
> + */
> +struct d0_tper_features {
> +	/*
> +	 * supported_features bits:
> +	 * bit 7: reserved
> +	 * bit 6: com ID management
> +	 * bit 5: reserved
> +	 * bit 4: streaming support
> +	 * bit 3: buffer management
> +	 * bit 2: ACK/NACK
> +	 * bit 1: async
> +	 * bit 0: sync
> +	 */
> +	u8 supported_features;
> +	/*
> +	 * bytes 5 through 15 are reserved, but we represent the first 3 as
> +	 * u8 to keep the other two 32bits integers aligned.
> +	 */
> +	u8 reserved01[3];
> +	u32 reserved02;
> +	u32 reserved03;
> +};
> +
> +/*
> + * Locking Feature Descriptor. Contains flags indicating support for the
> + * locking features described in the OPAL specification. The names match the
> + * OPAL terminology
> + *
> + * code == 0x0002 in 2.00.100
> + */
> +struct d0_locking_features {
> +	/*
> +	 * supported_features bits:
> +	 * bits 6-7: reserved
> +	 * bit 5: MBR done
> +	 * bit 4: MBR enabled
> +	 * bit 3: media encryption
> +	 * bit 2: locked
> +	 * bit 1: locking enabled
> +	 * bit 0: locking supported
> +	 */
> +	u8 supported_features;
> +	/*
> +	 * bytes 5 through 15 are reserved, but we represent the first 3 as
> +	 * u8 to keep the other two 32bits integers aligned.
> +	 */
> +	u8 reserved01[3];
> +	u32 reserved02;
> +	u32 reserved03;
> +};
> +
> +/*
> + * Geometry Feature Descriptor. Contains flags indicating support for the
> + * geometry features described in the OPAL specification. The names match the
> + * OPAL terminology
> + *
> + * code == 0x0003 in 2.00.100
> + */
> +struct d0_geometry_features {
> +	/*
> +	 * skip 32 bits from header, needed to align the struct to 64 bits.
> +	 */
> +	u8 header[4];
> +	/*
> +	 * reserved01:
> +	 * bits 1-6: reserved
> +	 * bit 0: align
> +	 */
> +	u8 reserved01;
> +	u8 reserved02[7];
> +	u32 logical_block_size;
> +	u64 alignment_granularity;
> +	u64 lowest_aligned_lba;
> +};
> +
> +/*
> + * Enterprise SSC Feature
> + *
> + * code == 0x0100
> + */
> +struct d0_enterprise_ssc {
> +	u16 baseComID;
> +	u16 numComIDs;
> +	/* range_crossing:
> +	 * bits 1-6: reserved
> +	 * bit 0: range crossing
> +	 */
> +	u8 range_crossing;
> +	u8 reserved01;
> +	u16 reserved02;
> +	u32 reserved03;
> +	u32 reserved04;
> +};
> +
> +/*
> + * Opal V1 feature
> + *
> + * code == 0x0200
> + */
> +struct d0_opal_v100 {
> +	u16 baseComID;
> +	u16 numComIDs;
> +};
> +
> +/*
> + * Single User Mode feature
> + *
> + * code == 0x0201
> + */
> +struct d0_single_user_mode {
> +	u32 num_locking_objects;
> +	/* reserved01:
> +	 * bit 0: any
> +	 * bit 1: all
> +	 * bit 2: policy
> +	 * bits 3-7: reserved
> +	 */
> +	u8 reserved01;
> +	u8 reserved02;
> +	u16 reserved03;
> +	u32 reserved04;
> +};
> +
> +/*
> + * Additonal Datastores feature
> + *
> + * code == 0x0202
> + */
> +struct d0_datastore_table {
> +	u16 reserved01;
> +	u16 max_tables;
> +	u32 max_size_tables;
> +	u32 table_size_alignment;
> +};
> +
> +/*
> + * OPAL 2.0 feature
> + *
> + * code == 0x0203
> + */
> +struct d0_opal_v200 {
> +	u16 baseComID;
> +	u16 numComIDs;
> +	/* range_crossing:
> +	 * bits 1-6: reserved
> +	 * bit 0: range crossing
> +	 */
> +	u8 range_crossing;
> +	/* num_locking_admin_auth:
> +	 * not aligned to 16 bits, so use two u8.
> +	 * stored in big endian:
> +	 * 0: MSB
> +	 * 1: LSB
> +	 */
> +	u8 num_locking_admin_auth[2];
> +	/* num_locking_user_auth:
> +	 * not aligned to 16 bits, so use two u8.
> +	 * stored in big endian:
> +	 * 0: MSB
> +	 * 1: LSB
> +	 */
> +	u8 num_locking_user_auth[2];
> +	u8 initialPIN;
> +	u8 revertedPIN;
> +	u8 reserved01;
> +	u32 reserved02;
> +};
> +
> +/* Union of features used to parse the discovery 0 response */
> +struct d0_features {
> +	u16 code;
> +	/*
> +	 * r_version bits:
> +	 * bits 4-7: version
> +	 * bits 0-3: reserved
> +	 */
> +	u8 r_version;
> +	u8 length;
> +	u8 features[];
> +};
> +
> +struct key *request_user_key(const char *master_desc, const u8 **master_key,
> +			     size_t *master_keylen);
> +
> +#endif /* _NVME_OPAL_INTERNAL_H */
> diff --git a/lib/sed-opal_key.c b/lib/sed-opal_key.c
> new file mode 100644
> index 0000000..0b4de01
> --- /dev/null
> +++ b/lib/sed-opal_key.c
> @@ -0,0 +1,46 @@
> +/*
> + * Copyright ? 2016 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Author:
> + *    Rafael Antognolli <rafael.antognolli at intel.com>
> + */
> +
> +#include <linux/key.h>
> +#include "sed-opal_internal.h"
> +
> +struct key *request_user_key(const char *master_desc, const u8 **master_key,
> +			     size_t *master_keylen)
> +{
> +	const struct user_key_payload *upayload;
> +	struct key *ukey;
> +
> +	ukey = request_key(&key_type_user, master_desc, NULL);
> +	if (IS_ERR(ukey))
> +		goto error;
> +
> +	down_read(&ukey->sem);
> +	upayload = user_key_payload(ukey);
> +	*master_key = upayload->data;
> +	*master_keylen = upayload->datalen;
> +error:
> +	return ukey;
> +}
> diff --git a/lib/sed.c b/lib/sed.c
> new file mode 100644
> index 0000000..06cacd9
> --- /dev/null
> +++ b/lib/sed.c
> @@ -0,0 +1,303 @@
> +#include <linux/blkdev.h>
> +#include <linux/sed.h>
> +#include <linux/sed-opal.h>
> +
> +#ifndef CONFIG_SED_OPAL
> +static int sed_opal_save(struct block_device *bdev, struct sed_key *sed)
> +	{ return -EOPNOTSUPP; }
> +static int sed_opal_lock_unlock(struct block_device *bdev, struct sed_key *key)
> +	{ return -EOPNOTSUPP; }
> +static int sed_opal_take_ownership(struct block_device *bdev, struct sed_key *key)
> +	{ return -EOPNOTSUPP; }
> +static int sed_opal_activate_lsp(struct block_device *bdev, struct sed_key *key)
> +	{ return -EOPNOTSUPP; }
> +static int sed_opal_set_pw(struct block_device *bdev, struct sed_key *key)
> +	{ return -EOPNOTSUPP; }
> +static int sed_opal_activate_user(struct block_device *bdev, struct sed_key *key)
> +	{ return -EOPNOTSUPP; }
> +static int sed_opal_reverttper(struct block_device *bdev, struct sed_key *key)
> +	{ return -EOPNOTSUPP; }
> +static int sed_opal_setup_locking_range(struct block_device *bdev, struct sed_key *key)
> +	{ return -EOPNOTSUPP; }
> +static int sed_opal_adduser_to_lr(struct block_device *bdev, struct sed_key *key)
> +	{ return -EOPNOTSUPP; }
> +static int sed_opal_do_mbr(struct block_device *bdev, struct sed_key *key)
> +	{ return -EOPNOTSUPP; }
> +static int sed_opal_erase_lr(struct block_device *bdev, struct sed_key *key)
> +	{ return -EOPNOTSUPP; }
> +
> +#else
> +
> +static int sed_opal_save(struct block_device *bdev, struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
You might consider pulling this boilerplate out into something like:
static inline bool bdev_sec_capable(struct block_device *bdev)
{
	return bdev && bdev->bd_disk && bdev->bd_disk->fops &&
	       bdev->bd_disk->fops->sec_ops;
}


> +
> +	return opal_save(bdev, key);
> +}
> +
> +static int sed_opal_lock_unlock(struct block_device *bdev, struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_lock_unlock(bdev, key);
> +}
> +
> +static int sed_opal_take_ownership(struct block_device *bdev,
> +				   struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_take_ownership(bdev, key);
> +}
> +
> +static int sed_opal_activate_lsp(struct block_device *bdev,
> +				 struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_activate_lsp(bdev, key);
> +}
> +
> +static int sed_opal_set_pw(struct block_device *bdev,
> +			   struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_set_new_pw(bdev, key);
> +}
> +
> +static int sed_opal_activate_user(struct block_device *bdev,
> +				  struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_activate_user(bdev, key);
> +}
> +
> +static int sed_opal_reverttper(struct block_device *bdev,
> +			       struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_reverttper(bdev, key);
> +}
> +
> +static int sed_opal_setup_lr(struct block_device *bdev,
> +			     struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_setup_locking_range(bdev, key);
> +}
> +
> +static int sed_opal_adduser_to_lr(struct block_device *bdev,
> +			     struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_add_user_to_lr(bdev, key);
> +}
> +
> +static int sed_opal_do_mbr(struct block_device *bdev,
> +			   struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_enable_disable_shadow_mbr(bdev, key);
> +}
> +
> +static int sed_opal_erase_lr(struct block_device *bdev,
> +			     struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_erase_locking_range(bdev, key);
> +}
> +#endif
> +
> +int sed_save(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL_LOCK_UNLOCK:
> +		return sed_opal_save(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +int sed_lock_unlock(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL_LOCK_UNLOCK:
> +		return sed_opal_lock_unlock(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +int sed_take_ownership(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL:
> +		return sed_opal_take_ownership(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +int sed_activate_lsp(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL:
> +		return sed_opal_activate_lsp(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +int sed_set_pw(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL_PW:
> +		return sed_opal_set_pw(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +int sed_activate_user(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL_ACT_USR:
> +		return sed_opal_activate_user(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +int sed_reverttper(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL:
> +		return sed_opal_reverttper(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +int sed_setup_locking_range(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL_LR_SETUP:
> +		return sed_opal_setup_lr(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +int sed_adduser_to_lr(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL_LOCK_UNLOCK:
> +		return sed_opal_adduser_to_lr(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +int sed_do_mbr(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL_MBR_DATA:
> +		return sed_opal_do_mbr(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +int sed_erase_lr(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL:
> +		return sed_opal_erase_lr(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> -- 
> 2.7.4
> 

  reply	other threads:[~2016-11-01 18:56 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-31 21:58 [RFC PATCH 0/6] Sed Opal Scott Bauer
2016-10-31 21:58 ` Scott Bauer
2016-10-31 21:58 ` [RFC PATCH 1/6] Include: Add definitions for sed Scott Bauer
2016-10-31 21:58   ` Scott Bauer
2016-10-31 21:58 ` [RFC PATCH 2/6] lib: Add Sed-opal library Scott Bauer
2016-10-31 21:58   ` Scott Bauer
2016-11-01 18:56   ` Jon Derrick [this message]
2016-11-01 18:56     ` Jon Derrick
2016-10-31 21:58 ` [RFC PATCH 3/6] lib: Add Sed to Kconfig and Makefile Scott Bauer
2016-10-31 21:58   ` Scott Bauer
2016-10-31 21:58 ` [RFC PATCH 4/6] include: Add sec_ops to block device operations Scott Bauer
2016-10-31 21:58   ` Scott Bauer
2016-10-31 21:58 ` [RFC PATCH 5/6] nvme: Add unlock_from_suspend Scott Bauer
2016-10-31 21:58   ` Scott Bauer
2016-11-01  8:18   ` Sagi Grimberg
2016-11-01  8:18     ` Sagi Grimberg
2016-11-01 13:57     ` Christoph Hellwig
2016-11-01 13:57       ` Christoph Hellwig
2016-11-01 14:40       ` Scott Bauer
2016-11-01 14:40         ` Scott Bauer
2016-11-10 23:01       ` Scott Bauer
2016-11-10 23:01         ` Scott Bauer
2016-11-10 23:23         ` Keith Busch
2016-11-10 23:23           ` Keith Busch
2016-11-10 23:19           ` Christoph Hellwig
2016-11-10 23:19             ` Christoph Hellwig
2016-11-07 18:45     ` Keith Busch
2016-11-07 18:45       ` Keith Busch
2016-11-07 18:33       ` Scott Bauer
2016-11-07 18:33         ` Scott Bauer
2016-10-31 21:58 ` [RFC PATCH 6/6] block: ioctl: Wire up Sed to block ioctls Scott Bauer
2016-10-31 21:58   ` Scott Bauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161101185611.GA1999@localhost.localdomain \
    --to=jonathan.derrick@intel.com \
    --cc=Rafael.Antognolli@intel.com \
    --cc=axboe@fb.com \
    --cc=hch@infradead.org \
    --cc=j.naumann@fu-berlin.de \
    --cc=keith.busch@intel.com \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-nvme@lists.infradead.org \
    --cc=scott.bauer@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.