mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-14 08:03:34 +00:00
initial key provisioning demo working
This commit is contained in:
parent
86845dd093
commit
bc6ec8caf4
13 changed files with 1291 additions and 820 deletions
256
precursors/rom.db
Normal file → Executable file
256
precursors/rom.db
Normal file → Executable file
|
|
@ -1,128 +1,128 @@
|
|||
KEYROM 0 A SLICE_X36Y50 b'c3a0e2b132d2f31e'
|
||||
KEYROM 0 B SLICE_X36Y50 b'2ca56f199524c45d'
|
||||
KEYROM 0 C SLICE_X36Y50 b'eda510da53bf8cc4'
|
||||
KEYROM 0 D SLICE_X36Y50 b'c188087aa2ec96d0'
|
||||
KEYROM 1 A SLICE_X37Y50 b'7ee6ea370ad2fe5c'
|
||||
KEYROM 1 B SLICE_X37Y50 b'4aa8f7fcdd02326f'
|
||||
KEYROM 1 C SLICE_X37Y50 b'd847ed542da2a44f'
|
||||
KEYROM 1 D SLICE_X37Y50 b'851060cd1389a654'
|
||||
KEYROM 2 A SLICE_X36Y51 b'0465fe16934897a2'
|
||||
KEYROM 2 B SLICE_X36Y51 b'26ce3719ef29809b'
|
||||
KEYROM 2 C SLICE_X36Y51 b'70b7fa0f33ee7f0c'
|
||||
KEYROM 2 D SLICE_X36Y51 b'b47f2cbdc35c9247'
|
||||
KEYROM 3 A SLICE_X37Y51 b'9a4d29fe5eec4757'
|
||||
KEYROM 3 B SLICE_X37Y51 b'7df4a143ae4a7caa'
|
||||
KEYROM 3 C SLICE_X37Y51 b'1af63092ba3fefa2'
|
||||
KEYROM 3 D SLICE_X37Y51 b'3f1c14d0ba5ba72e'
|
||||
KEYROM 4 A SLICE_X36Y52 b'40c14b1e5630c3a4'
|
||||
KEYROM 4 B SLICE_X36Y52 b'b871f9de6c4b74c0'
|
||||
KEYROM 4 C SLICE_X36Y52 b'84e1def501c588fb'
|
||||
KEYROM 4 D SLICE_X36Y52 b'e7553ded600994ac'
|
||||
KEYROM 5 A SLICE_X37Y52 b'd20804a0ed7efe1c'
|
||||
KEYROM 5 B SLICE_X37Y52 b'ba36a98a7010e5e5'
|
||||
KEYROM 5 C SLICE_X37Y52 b'd5907c3f23a1442d'
|
||||
KEYROM 5 D SLICE_X37Y52 b'd65c5d2d7c5a3798'
|
||||
KEYROM 6 A SLICE_X36Y53 b'2d8c6317e1f6b8a1'
|
||||
KEYROM 6 B SLICE_X36Y53 b'de9ed0b5156ee3d3'
|
||||
KEYROM 6 C SLICE_X36Y53 b'11f355c942161ec7'
|
||||
KEYROM 6 D SLICE_X36Y53 b'fbd0d6b72ef33027'
|
||||
KEYROM 7 A SLICE_X37Y53 b'914b578244116537'
|
||||
KEYROM 7 B SLICE_X37Y53 b'7f6db6dd8ef69b39'
|
||||
KEYROM 7 C SLICE_X37Y53 b'32e3e4f56a617aa2'
|
||||
KEYROM 7 D SLICE_X37Y53 b'8ea9b280f9a9e78a'
|
||||
KEYROM 8 A SLICE_X36Y54 b'be03b1a096290f64'
|
||||
KEYROM 8 B SLICE_X36Y54 b'ffa98648a3196b8d'
|
||||
KEYROM 8 C SLICE_X36Y54 b'88bac8cd859e7963'
|
||||
KEYROM 8 D SLICE_X36Y54 b'be0cf1198b720088'
|
||||
KEYROM 9 A SLICE_X37Y54 b'150b03fdc35cffb8'
|
||||
KEYROM 9 B SLICE_X37Y54 b'10efffba5c00dc08'
|
||||
KEYROM 9 C SLICE_X37Y54 b'199523c7ad081e0e'
|
||||
KEYROM 9 D SLICE_X37Y54 b'3dc86a72c75ad38a'
|
||||
KEYROM 10 A SLICE_X36Y55 b'3ab20094c1bc3788'
|
||||
KEYROM 10 B SLICE_X36Y55 b'672ce21657d15645'
|
||||
KEYROM 10 C SLICE_X36Y55 b'999635ee37381c37'
|
||||
KEYROM 10 D SLICE_X36Y55 b'd85f5b0df1be66fa'
|
||||
KEYROM 11 A SLICE_X37Y55 b'01fc41acd00c0376'
|
||||
KEYROM 11 B SLICE_X37Y55 b'c83f7effdd5e2865'
|
||||
KEYROM 11 C SLICE_X37Y55 b'4bb31612900f38aa'
|
||||
KEYROM 11 D SLICE_X37Y55 b'3346dd9800df334f'
|
||||
KEYROM 12 A SLICE_X36Y56 b'5547b1eae3398d4f'
|
||||
KEYROM 12 B SLICE_X36Y56 b'c2a761373bdfeadc'
|
||||
KEYROM 12 C SLICE_X36Y56 b'1c9c0e67e0d6dd6d'
|
||||
KEYROM 12 D SLICE_X36Y56 b'75eea4f26017e9d7'
|
||||
KEYROM 13 A SLICE_X37Y56 b'3e57f26d8bd60162'
|
||||
KEYROM 13 B SLICE_X37Y56 b'dec91b14c25e2f66'
|
||||
KEYROM 13 C SLICE_X37Y56 b'73b87b32387b7298'
|
||||
KEYROM 13 D SLICE_X37Y56 b'2d5b8b7306a65caa'
|
||||
KEYROM 14 A SLICE_X36Y57 b'4e09d069d040baf6'
|
||||
KEYROM 14 B SLICE_X36Y57 b'a9d2df3f8954f7a8'
|
||||
KEYROM 14 C SLICE_X36Y57 b'0b696c38ed59c638'
|
||||
KEYROM 14 D SLICE_X36Y57 b'55871008fee18aa2'
|
||||
KEYROM 15 A SLICE_X37Y57 b'e79e503241d13516'
|
||||
KEYROM 15 B SLICE_X37Y57 b'92a6565b4a7664c0'
|
||||
KEYROM 15 C SLICE_X37Y57 b'069895a86f2c79e9'
|
||||
KEYROM 15 D SLICE_X37Y57 b'0edfc25b603d6cce'
|
||||
KEYROM 16 A SLICE_X36Y58 b'1b1a656e9cfa599b'
|
||||
KEYROM 16 B SLICE_X36Y58 b'5bec33557444d5ba'
|
||||
KEYROM 16 C SLICE_X36Y58 b'008f6b2f81c29561'
|
||||
KEYROM 16 D SLICE_X36Y58 b'5c04e9520239826e'
|
||||
KEYROM 17 A SLICE_X37Y58 b'd66fe6aaa356493a'
|
||||
KEYROM 17 B SLICE_X37Y58 b'05eff990ab0dbca8'
|
||||
KEYROM 17 C SLICE_X37Y58 b'01757c16edf587e2'
|
||||
KEYROM 17 D SLICE_X37Y58 b'1b4f6b04aabaaba6'
|
||||
KEYROM 18 A SLICE_X36Y59 b'85db56743658bd5c'
|
||||
KEYROM 18 B SLICE_X36Y59 b'd0805089c70677e6'
|
||||
KEYROM 18 C SLICE_X36Y59 b'b5791a9510679b1f'
|
||||
KEYROM 18 D SLICE_X36Y59 b'7007f1bc3e5842d0'
|
||||
KEYROM 19 A SLICE_X37Y59 b'bf16ac68faa50b01'
|
||||
KEYROM 19 B SLICE_X37Y59 b'efeaab7b47b6403f'
|
||||
KEYROM 19 C SLICE_X37Y59 b'8dd5405a4eab5a08'
|
||||
KEYROM 19 D SLICE_X37Y59 b'd25414a37496bd3d'
|
||||
KEYROM 20 A SLICE_X36Y60 b'bf3ee8312bd0870b'
|
||||
KEYROM 20 B SLICE_X36Y60 b'7491ab56dafbef9c'
|
||||
KEYROM 20 C SLICE_X36Y60 b'20356eda0267c983'
|
||||
KEYROM 20 D SLICE_X36Y60 b'a9d60b973dd19a85'
|
||||
KEYROM 21 A SLICE_X37Y60 b'ebcde3cbcbea9168'
|
||||
KEYROM 21 B SLICE_X37Y60 b'718daec18f71e60f'
|
||||
KEYROM 21 C SLICE_X37Y60 b'3225102d796a019a'
|
||||
KEYROM 21 D SLICE_X37Y60 b'b97ee41b5d611eb2'
|
||||
KEYROM 22 A SLICE_X36Y61 b'90483617e30e112d'
|
||||
KEYROM 22 B SLICE_X36Y61 b'ebd4e144c76ad69e'
|
||||
KEYROM 22 C SLICE_X36Y61 b'836adbc2d2b9135b'
|
||||
KEYROM 22 D SLICE_X36Y61 b'8a6f50d59c5222f3'
|
||||
KEYROM 23 A SLICE_X37Y61 b'6fcb8d91c93b88e7'
|
||||
KEYROM 23 B SLICE_X37Y61 b'33fd35b6775ee619'
|
||||
KEYROM 23 C SLICE_X37Y61 b'ded05bf353967b43'
|
||||
KEYROM 23 D SLICE_X37Y61 b'0847bab859ee97c3'
|
||||
KEYROM 24 A SLICE_X36Y62 b'3e7f120884e00484'
|
||||
KEYROM 24 B SLICE_X36Y62 b'a0d25326292916af'
|
||||
KEYROM 24 C SLICE_X36Y62 b'f00d5be2a1dd5028'
|
||||
KEYROM 24 D SLICE_X36Y62 b'040270fb966aeadb'
|
||||
KEYROM 25 A SLICE_X37Y62 b'982ade51ade336fe'
|
||||
KEYROM 25 B SLICE_X37Y62 b'1aec6c88e99d8be2'
|
||||
KEYROM 25 C SLICE_X37Y62 b'f8ac7f661d70d002'
|
||||
KEYROM 25 D SLICE_X37Y62 b'9d5f71254a856e8e'
|
||||
KEYROM 26 A SLICE_X36Y63 b'c603bbcbdb8a1b4d'
|
||||
KEYROM 26 B SLICE_X36Y63 b'3b4ead9cf990e112'
|
||||
KEYROM 26 C SLICE_X36Y63 b'd825e8f3a34d29d4'
|
||||
KEYROM 26 D SLICE_X36Y63 b'6dbccc3bca6b3534'
|
||||
KEYROM 27 A SLICE_X37Y63 b'12ba32f22165572d'
|
||||
KEYROM 27 B SLICE_X37Y63 b'98f94f235907579d'
|
||||
KEYROM 27 C SLICE_X37Y63 b'd184af07800e0ecc'
|
||||
KEYROM 27 D SLICE_X37Y63 b'655e262876efc1c3'
|
||||
KEYROM 28 A SLICE_X36Y64 b'849ead535c1b4fce'
|
||||
KEYROM 28 B SLICE_X36Y64 b'f59721f21bbaf649'
|
||||
KEYROM 28 C SLICE_X36Y64 b'cc4c9a7717eb4dd4'
|
||||
KEYROM 28 D SLICE_X36Y64 b'618ed39fbed2924a'
|
||||
KEYROM 29 A SLICE_X37Y64 b'36513623ac1716a6'
|
||||
KEYROM 29 B SLICE_X37Y64 b'038b21fdaffdcda1'
|
||||
KEYROM 29 C SLICE_X37Y64 b'585ef63e34650453'
|
||||
KEYROM 29 D SLICE_X37Y64 b'eaece498c0c8ee5d'
|
||||
KEYROM 30 A SLICE_X36Y65 b'3ce75a293ae01957'
|
||||
KEYROM 30 B SLICE_X36Y65 b'bc940fd0f2ce9360'
|
||||
KEYROM 30 C SLICE_X36Y65 b'14b887863092fd13'
|
||||
KEYROM 30 D SLICE_X36Y65 b'a8964b349a1b7c17'
|
||||
KEYROM 31 A SLICE_X37Y65 b'f3b82c2e1c20553c'
|
||||
KEYROM 31 B SLICE_X37Y65 b'9f2aabc29ba378f8'
|
||||
KEYROM 31 C SLICE_X37Y65 b'0f98135a942e951b'
|
||||
KEYROM 31 D SLICE_X37Y65 b'b7ef321d5b96792a'
|
||||
KEYROM 0 A SLICE_X36Y50 b'ed9040309fce38f4'
|
||||
KEYROM 0 B SLICE_X36Y50 b'34b83a94e4408416'
|
||||
KEYROM 0 C SLICE_X36Y50 b'8f088d95d0241a29'
|
||||
KEYROM 0 D SLICE_X36Y50 b'71976c7c19e9b004'
|
||||
KEYROM 1 A SLICE_X37Y50 b'23147e30bff2ec9a'
|
||||
KEYROM 1 B SLICE_X37Y50 b'1fd3c7d928865270'
|
||||
KEYROM 1 C SLICE_X37Y50 b'69affdc0d64bce09'
|
||||
KEYROM 1 D SLICE_X37Y50 b'7a5d619fdd90768c'
|
||||
KEYROM 2 A SLICE_X36Y51 b'e6a75fea68b97646'
|
||||
KEYROM 2 B SLICE_X36Y51 b'3bbe4fd7491feae7'
|
||||
KEYROM 2 C SLICE_X36Y51 b'8f1ce05eb6df82cf'
|
||||
KEYROM 2 D SLICE_X36Y51 b'27262a3adbb299bb'
|
||||
KEYROM 3 A SLICE_X37Y51 b'f51fe08930b42539'
|
||||
KEYROM 3 B SLICE_X37Y51 b'fe0f77932c0955be'
|
||||
KEYROM 3 C SLICE_X37Y51 b'75b2d1f824733c6e'
|
||||
KEYROM 3 D SLICE_X37Y51 b'd7d7ba4db2a43551'
|
||||
KEYROM 4 A SLICE_X36Y52 b'01adb0f69b2445b6'
|
||||
KEYROM 4 B SLICE_X36Y52 b'f9615dc2835077a9'
|
||||
KEYROM 4 C SLICE_X36Y52 b'48b9726cdadf5f5c'
|
||||
KEYROM 4 D SLICE_X36Y52 b'b04e43398e8a5a48'
|
||||
KEYROM 5 A SLICE_X37Y52 b'ff7bd4295aabdd2d'
|
||||
KEYROM 5 B SLICE_X37Y52 b'71ed1b78bf6abef1'
|
||||
KEYROM 5 C SLICE_X37Y52 b'711b0d7da395db20'
|
||||
KEYROM 5 D SLICE_X37Y52 b'bab4a809cb8d5749'
|
||||
KEYROM 6 A SLICE_X36Y53 b'4d30fac41aa32b0f'
|
||||
KEYROM 6 B SLICE_X36Y53 b'43b00f6dcac70852'
|
||||
KEYROM 6 C SLICE_X36Y53 b'ad4003d496e1977f'
|
||||
KEYROM 6 D SLICE_X36Y53 b'4ae9ec045604171d'
|
||||
KEYROM 7 A SLICE_X37Y53 b'926d630da7b7a38f'
|
||||
KEYROM 7 B SLICE_X37Y53 b'ea9dcfbcee0e3e27'
|
||||
KEYROM 7 C SLICE_X37Y53 b'331310550f7be1a3'
|
||||
KEYROM 7 D SLICE_X37Y53 b'86654bf903647983'
|
||||
KEYROM 8 A SLICE_X36Y54 b'5faf7f97fd1adda9'
|
||||
KEYROM 8 B SLICE_X36Y54 b'bd9e98995dfeb80e'
|
||||
KEYROM 8 C SLICE_X36Y54 b'ccc154e624fa6d30'
|
||||
KEYROM 8 D SLICE_X36Y54 b'6d4cf1460bbcc9d7'
|
||||
KEYROM 9 A SLICE_X37Y54 b'61a5187dac4451d5'
|
||||
KEYROM 9 B SLICE_X37Y54 b'b0ad0aeed2998bc1'
|
||||
KEYROM 9 C SLICE_X37Y54 b'f21d761d350fc65c'
|
||||
KEYROM 9 D SLICE_X37Y54 b'b12550f563825b1e'
|
||||
KEYROM 10 A SLICE_X36Y55 b'fd44ec8a47c67607'
|
||||
KEYROM 10 B SLICE_X36Y55 b'6f73609c3f474a99'
|
||||
KEYROM 10 C SLICE_X36Y55 b'97f3f40b00eff415'
|
||||
KEYROM 10 D SLICE_X36Y55 b'd9a8030e01d2e969'
|
||||
KEYROM 11 A SLICE_X37Y55 b'b69db3f2c7383567'
|
||||
KEYROM 11 B SLICE_X37Y55 b'c84e2d58eed1667f'
|
||||
KEYROM 11 C SLICE_X37Y55 b'8de4bf137da8b4a5'
|
||||
KEYROM 11 D SLICE_X37Y55 b'4b44f068e3b6e954'
|
||||
KEYROM 12 A SLICE_X36Y56 b'9f9dfa17fd8f813b'
|
||||
KEYROM 12 B SLICE_X36Y56 b'd7e2dc46e49beed5'
|
||||
KEYROM 12 C SLICE_X36Y56 b'3c147b86326a0df7'
|
||||
KEYROM 12 D SLICE_X36Y56 b'6de9236fe18c43bb'
|
||||
KEYROM 13 A SLICE_X37Y56 b'f96f763f484a7293'
|
||||
KEYROM 13 B SLICE_X37Y56 b'ea9d3dc73170641a'
|
||||
KEYROM 13 C SLICE_X37Y56 b'2045bb3e568b0ef8'
|
||||
KEYROM 13 D SLICE_X37Y56 b'2ce220df70dfe05d'
|
||||
KEYROM 14 A SLICE_X36Y57 b'0fd2db99d978d460'
|
||||
KEYROM 14 B SLICE_X36Y57 b'83ce09c09327ae22'
|
||||
KEYROM 14 C SLICE_X36Y57 b'195e32c556a026fd'
|
||||
KEYROM 14 D SLICE_X36Y57 b'23627d617f5baf71'
|
||||
KEYROM 15 A SLICE_X37Y57 b'c7f24e5f55a9cca9'
|
||||
KEYROM 15 B SLICE_X37Y57 b'7820cea9a62feef3'
|
||||
KEYROM 15 C SLICE_X37Y57 b'baf6949fc5db190d'
|
||||
KEYROM 15 D SLICE_X37Y57 b'c208af523a7d55ef'
|
||||
KEYROM 16 A SLICE_X36Y58 b'b1445a38b8cec3ec'
|
||||
KEYROM 16 B SLICE_X36Y58 b'2e694e04676b83c6'
|
||||
KEYROM 16 C SLICE_X36Y58 b'33b1fbd89e0b2d53'
|
||||
KEYROM 16 D SLICE_X36Y58 b'74d20b1bc8765902'
|
||||
KEYROM 17 A SLICE_X37Y58 b'65bdef7af5c88f77'
|
||||
KEYROM 17 B SLICE_X37Y58 b'182f425b728098e6'
|
||||
KEYROM 17 C SLICE_X37Y58 b'26a6e4b72e49a038'
|
||||
KEYROM 17 D SLICE_X37Y58 b'476e499924be15c0'
|
||||
KEYROM 18 A SLICE_X36Y59 b'b78c1c5cc2aa57a1'
|
||||
KEYROM 18 B SLICE_X36Y59 b'31384d4342a6fda5'
|
||||
KEYROM 18 C SLICE_X36Y59 b'05ae9c252ac885ce'
|
||||
KEYROM 18 D SLICE_X36Y59 b'c96968631e3f7f78'
|
||||
KEYROM 19 A SLICE_X37Y59 b'634d2885ce6e5855'
|
||||
KEYROM 19 B SLICE_X37Y59 b'a3cf9e2e72e6e792'
|
||||
KEYROM 19 C SLICE_X37Y59 b'581ffd047adcc9ea'
|
||||
KEYROM 19 D SLICE_X37Y59 b'2f64b2ce422d5531'
|
||||
KEYROM 20 A SLICE_X36Y60 b'7e329f3ca0aaa48e'
|
||||
KEYROM 20 B SLICE_X36Y60 b'aea96c4e160d7c23'
|
||||
KEYROM 20 C SLICE_X36Y60 b'6ae6580d67e7ff89'
|
||||
KEYROM 20 D SLICE_X36Y60 b'5474386b42cab7f1'
|
||||
KEYROM 21 A SLICE_X37Y60 b'3f9bd1bd08d4aff4'
|
||||
KEYROM 21 B SLICE_X37Y60 b'e56106594063c796'
|
||||
KEYROM 21 C SLICE_X37Y60 b'2195de30ceb285a2'
|
||||
KEYROM 21 D SLICE_X37Y60 b'6334c328f262238f'
|
||||
KEYROM 22 A SLICE_X36Y61 b'c7864968fa48d4fb'
|
||||
KEYROM 22 B SLICE_X36Y61 b'539340a6115a09de'
|
||||
KEYROM 22 C SLICE_X36Y61 b'5a481886017ce135'
|
||||
KEYROM 22 D SLICE_X36Y61 b'53ab6dd8014367e1'
|
||||
KEYROM 23 A SLICE_X37Y61 b'a96ce894e8ef46bc'
|
||||
KEYROM 23 B SLICE_X37Y61 b'1bb558f3736ff921'
|
||||
KEYROM 23 C SLICE_X37Y61 b'5f317c906fda756e'
|
||||
KEYROM 23 D SLICE_X37Y61 b'a09db3281b82fcf1'
|
||||
KEYROM 24 A SLICE_X36Y62 b'916fb25b3c623029'
|
||||
KEYROM 24 B SLICE_X36Y62 b'3c36f54ab0b983c3'
|
||||
KEYROM 24 C SLICE_X36Y62 b'564c5c49176dccd2'
|
||||
KEYROM 24 D SLICE_X36Y62 b'6b2a7d1cb3402096'
|
||||
KEYROM 25 A SLICE_X37Y62 b'dfd1cc0ccc9d6375'
|
||||
KEYROM 25 B SLICE_X37Y62 b'773dc64635af690c'
|
||||
KEYROM 25 C SLICE_X37Y62 b'87958a06b32192f6'
|
||||
KEYROM 25 D SLICE_X37Y62 b'a9f627a1e12ff5fb'
|
||||
KEYROM 26 A SLICE_X36Y63 b'e848ef1676025ddb'
|
||||
KEYROM 26 B SLICE_X36Y63 b'631c42f2972d8f4e'
|
||||
KEYROM 26 C SLICE_X36Y63 b'e1ba5f1db6c1213e'
|
||||
KEYROM 26 D SLICE_X36Y63 b'd0a6beb90ebfa1ad'
|
||||
KEYROM 27 A SLICE_X37Y63 b'aa6f2108de94b9d7'
|
||||
KEYROM 27 B SLICE_X37Y63 b'94fdad0d7e5e032a'
|
||||
KEYROM 27 C SLICE_X37Y63 b'cb3a7ed9fa0c188c'
|
||||
KEYROM 27 D SLICE_X37Y63 b'd9115aa51962339f'
|
||||
KEYROM 28 A SLICE_X36Y64 b'88825ff323665a51'
|
||||
KEYROM 28 B SLICE_X36Y64 b'6e49b5862e6533ac'
|
||||
KEYROM 28 C SLICE_X36Y64 b'32fed356801273ab'
|
||||
KEYROM 28 D SLICE_X36Y64 b'37904b87d81a652a'
|
||||
KEYROM 29 A SLICE_X37Y64 b'4b5361b16868f5bd'
|
||||
KEYROM 29 B SLICE_X37Y64 b'ba9596094f9e43b9'
|
||||
KEYROM 29 C SLICE_X37Y64 b'ddabe807f246ff41'
|
||||
KEYROM 29 D SLICE_X37Y64 b'8815407bf7b4e684'
|
||||
KEYROM 30 A SLICE_X36Y65 b'0165ea750602f2be'
|
||||
KEYROM 30 B SLICE_X36Y65 b'3c62683258a88ef9'
|
||||
KEYROM 30 C SLICE_X36Y65 b'cc0c02f8539bf6d8'
|
||||
KEYROM 30 D SLICE_X36Y65 b'a1caffc2420bc6de'
|
||||
KEYROM 31 A SLICE_X37Y65 b'2a2894ffa957b03c'
|
||||
KEYROM 31 B SLICE_X37Y65 b'958c5490ad6c2e9b'
|
||||
KEYROM 31 C SLICE_X37Y65 b'f76c75011cdc2737'
|
||||
KEYROM 31 D SLICE_X37Y65 b'a734aab8e4d7f6eb'
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<device schemaVersion="1.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" >
|
||||
<vendor>litex</vendor>
|
||||
<name>SOC</name>
|
||||
<description><![CDATA[Litex SoC 2021-07-20 21:53:20]]></description>
|
||||
<description><![CDATA[Litex SoC 2021-08-06 13:55:31]]></description>
|
||||
|
||||
<addressUnitBits>8</addressUnitBits>
|
||||
<width>32</width>
|
||||
|
|
@ -1238,10 +1238,10 @@ register to disable individual events.]]></description>
|
|||
<register>
|
||||
<name>GIT_GITREV</name>
|
||||
<description><![CDATA[First 32-bits of the git revision. This documentation was built from git rev
|
||||
``e64c9cef``, so this value is 3863780591, which should be enough to check out
|
||||
``890b90e7``, so this value is 2299236583, which should be enough to check out
|
||||
the exact git version used to build this firmware.]]></description>
|
||||
<addressOffset>0x0014</addressOffset>
|
||||
<resetValue>0xe64c9cef</resetValue>
|
||||
<resetValue>0x890b90e7</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
@ -1258,7 +1258,7 @@ the exact git version used to build this firmware.]]></description>
|
|||
is ``1``, then the repository this was built from has one additional commit
|
||||
beyond the tag indicated in `MAJOR`, `MINOR`, and `REVISION`.]]></description>
|
||||
<addressOffset>0x0018</addressOffset>
|
||||
<resetValue>0x43</resetValue>
|
||||
<resetValue>0x46</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
@ -3584,7 +3584,7 @@ inject too fast.]]></description>
|
|||
<name>SEED1</name>
|
||||
<description><![CDATA[Bits 32-63 of `SEED_SEED`. Seed used for the build]]></description>
|
||||
<addressOffset>0x0000</addressOffset>
|
||||
<resetValue>0x19f188fb</resetValue>
|
||||
<resetValue>0x4f340196</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
@ -3599,7 +3599,7 @@ inject too fast.]]></description>
|
|||
<name>SEED0</name>
|
||||
<description><![CDATA[Bits 0-31 of `SEED_SEED`.]]></description>
|
||||
<addressOffset>0x0004</addressOffset>
|
||||
<resetValue>0x53401497</resetValue>
|
||||
<resetValue>0x77c237e8</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -89,7 +89,6 @@ pub(crate) struct UxContext {
|
|||
pub audioframe_id: Option<u32>,
|
||||
}
|
||||
const MAX_UX_CONTEXTS: usize = 6;
|
||||
pub(crate) const MAX_CANVASES: usize = 32;
|
||||
// const BOOT_APP_NAME: &'static str = "shellchat"; // this is the app to display on boot -- we will eventually need this once we have more than one app?
|
||||
pub const ROOTKEY_MODAL_NAME: &'static str = "rootkeys modal";
|
||||
const BOOT_CONTEXT_TRUSTLEVEL: u8 = 254;
|
||||
|
|
|
|||
|
|
@ -54,10 +54,25 @@
|
|||
"zh": "准备重启...",
|
||||
"en-audio": "Preparing to reboot."
|
||||
},
|
||||
"rootkeys.init.failure": {
|
||||
"en": "Process failed, aborting!",
|
||||
"zh": "正在初始化失败,中止!",
|
||||
"en-audio": "Process failed, aborting"
|
||||
"rootkeys.init.fail_verify": {
|
||||
"en": "Verification failed,\naborting!",
|
||||
"zh": "*missing*正在初始化失败,中止!",
|
||||
"en-audio": "Verification failed, aborting"
|
||||
},
|
||||
"rootkeys.init.fail_key": {
|
||||
"en": "FPGA key is wrong,\nborting!",
|
||||
"zh": "*missing*正在初始化失败,中止!",
|
||||
"en-audio": "FPGA key is wrong, aborting"
|
||||
},
|
||||
"rootkeys.init.fail_burn": {
|
||||
"en": "FLASH write problem,\naborting!",
|
||||
"zh": "*missing*正在初始化失败,中止!",
|
||||
"en-audio": "FLASH write problem, aborting"
|
||||
},
|
||||
"rootkeys.init.fail_alignment": {
|
||||
"en": "Internal alignment error,\naborting!",
|
||||
"zh": "*missing*正在初始化失败,中止!",
|
||||
"en-audio": "Internal alignment error, aborting"
|
||||
},
|
||||
"rootkeys.init.confirmation": {
|
||||
"en": "This cannot be undone.\nContinue?",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
pub(crate) const SERVER_NAME_KEYS: &str = "_Root key server and update manager_";
|
||||
#[allow(dead_code)]
|
||||
pub(crate) const ROOTKEY_MODAL_NAME: &'static str = "rootkeys modal";
|
||||
#[allow(dead_code)]
|
||||
pub(crate) const ROOTKEY_MENU_NAME: &'static str = "rootkeys menu";
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
|
@ -9,6 +10,8 @@ pub(crate) enum Opcode {
|
|||
/// use to check if we've been initialized
|
||||
KeysInitialized,
|
||||
|
||||
TestUx,
|
||||
|
||||
/// attempt to initialize keys on a brand new system. Does nothing if the keys are already provisioned.
|
||||
UxTryInitKeys,
|
||||
UxInitRequestPassword,
|
||||
|
|
@ -46,4 +49,12 @@ pub enum PasswordRetentionPolicy {
|
|||
pub enum PasswordType {
|
||||
Boot = 1,
|
||||
Update = 2,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum RootkeyResult {
|
||||
AlignmentError,
|
||||
KeyError,
|
||||
IntegrityError,
|
||||
FlashError,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
use gam::FONT_TOTAL_LEN;
|
||||
use ticktimer_server::Ticktimer;
|
||||
use utralib::generated::*;
|
||||
use xous::SOC_STAGING_GW_LEN;
|
||||
use crate::api::*;
|
||||
use core::num::NonZeroUsize;
|
||||
use num_traits::*;
|
||||
|
|
@ -13,7 +10,7 @@ use crate::bcrypt::*;
|
|||
use crate::api::PasswordType;
|
||||
|
||||
use core::convert::TryInto;
|
||||
use ed25519_dalek::{Keypair, Signature, Signer};
|
||||
use ed25519_dalek::{Keypair, Signature};
|
||||
use engine_sha512::*;
|
||||
use digest::Digest;
|
||||
use graphics_server::BulkRead;
|
||||
|
|
@ -83,13 +80,6 @@ pub(crate) mod keyrom_config {
|
|||
pub const INITIALIZED: KeyField = KeyField::new(1, 27);
|
||||
}
|
||||
|
||||
enum RootkeyResult {
|
||||
AlignmentError,
|
||||
KeyError,
|
||||
IntegrityError,
|
||||
FlashError,
|
||||
}
|
||||
|
||||
/// This structure is mapped into the password cache page and can be zero-ized at any time
|
||||
/// we avoid using fancy Rust structures because everything has to "make sense" after a forced zero-ization
|
||||
/// The "password" here is generated as follows:
|
||||
|
|
@ -131,20 +121,32 @@ const AES_BLOCKSIZE: usize = 16;
|
|||
/// stream from an arbitrary position.
|
||||
struct BitstreamOracle<'a> {
|
||||
bitstream: &'a [u8],
|
||||
cipher: Aes256,
|
||||
base: u32,
|
||||
dec_cipher: Aes256,
|
||||
enc_cipher: Aes256,
|
||||
iv: [u8; AES_BLOCKSIZE],
|
||||
/// subslice of the bitstream that contains just the encrypted area of the bitstream
|
||||
ciphertext: &'a [u8],
|
||||
ct_absolute_offset: usize,
|
||||
type2_count: u32,
|
||||
/// start of type2 data as an absolute offset in the overall bitstream
|
||||
type2_absolute_offset: usize,
|
||||
/// start of type2 data as an offset relative to the start of ciphertext
|
||||
type2_ciphertext_offset: usize,
|
||||
}
|
||||
impl<'a> BitstreamOracle<'a> {
|
||||
pub fn new(key: &'a[u8], bitstream: &'a[u8]) -> BitstreamOracle<'a> {
|
||||
/// oracle supports separate encryption and decryption keys, so that it may
|
||||
/// be used for re-encryption of bitstreams to a new key. If using it for patching,
|
||||
/// set the keys to the same value.
|
||||
pub fn new(dec_key: &'a[u8], enc_key: &'a[u8], bitstream: &'a[u8], base: u32) -> Result<BitstreamOracle<'a>, RootkeyResult> {
|
||||
let mut position: usize = 0;
|
||||
|
||||
// Search through the bitstream for the key words that define the IV and ciphertetx length.
|
||||
// This is done so that if extra headers are added or modified, the code doesn't break (versus coding in static offsets).
|
||||
let mut iv_pos = 0;
|
||||
let mut cwd = 0;
|
||||
while position < bitstream.len() {
|
||||
let cwd = u32::from_be_bytes(bitstream[position..position+4].try_into().unwrap());
|
||||
cwd = u32::from_be_bytes(bitstream[position..position+4].try_into().unwrap());
|
||||
if cwd == 0x3001_6004 {
|
||||
iv_pos = position + 4
|
||||
}
|
||||
|
|
@ -157,6 +159,10 @@ impl<'a> BitstreamOracle<'a> {
|
|||
let position = position + 4;
|
||||
let ciphertext_len = 4 * u32::from_be_bytes(bitstream[position..position+4].try_into().unwrap());
|
||||
let ciphertext_start = position + 4;
|
||||
if ciphertext_start & (AES_BLOCKSIZE - 1) != 0 {
|
||||
log::error!("Padding is incorrect on the bitstream. Check append_csr.py for padding and make sure you are burning gateware with --raw-binary, and not --bitstream as the latter strips padding from the top of the file.");
|
||||
return Err(RootkeyResult::AlignmentError)
|
||||
}
|
||||
log::info!("ciphertext len: {} bytes, start: 0x{:08x}", ciphertext_len, ciphertext_start);
|
||||
let ciphertext = &bitstream[ciphertext_start..ciphertext_start + ciphertext_len as usize];
|
||||
|
||||
|
|
@ -165,26 +171,93 @@ impl<'a> BitstreamOracle<'a> {
|
|||
log::info!("recovered iv (pre-flip): {:x?}", &bitstream[iv_pos..iv_pos + AES_BLOCKSIZE]);
|
||||
log::info!("recovered iv : {:x?}", &iv_bytes);
|
||||
|
||||
let cipher = Aes256::new(key.try_into().unwrap());
|
||||
let dec_cipher = Aes256::new(dec_key.try_into().unwrap());
|
||||
let enc_cipher = Aes256::new(enc_key.try_into().unwrap());
|
||||
|
||||
BitstreamOracle {
|
||||
let mut oracle = BitstreamOracle {
|
||||
bitstream,
|
||||
cipher,
|
||||
base,
|
||||
dec_cipher,
|
||||
enc_cipher,
|
||||
iv: iv_bytes,
|
||||
ciphertext,
|
||||
ct_absolute_offset: ciphertext_start,
|
||||
type2_count: 0,
|
||||
type2_absolute_offset: 0,
|
||||
type2_ciphertext_offset: 0,
|
||||
};
|
||||
|
||||
// search forward for the "type 2" region in the first kilobyte of plaintext
|
||||
// type2 is where regular dataframes start, and we can compute offsets for patching
|
||||
// based on this.
|
||||
let mut first_block: [u8; 1024] = [0; 1024];
|
||||
oracle.decrypt(0, &mut first_block);
|
||||
|
||||
// check that the plaintext header has a well-known sequence in it -- sanity check the AES key
|
||||
let mut pass = true;
|
||||
for &b in first_block[32..64].iter() {
|
||||
if b != 0x6C {
|
||||
pass = false;
|
||||
}
|
||||
}
|
||||
if !pass {
|
||||
log::error!("hmac_header did not decrypt correctly: {:x?}", &first_block[..64]);
|
||||
return Err(RootkeyResult::KeyError)
|
||||
}
|
||||
|
||||
// start searching for the commands *after* the IV and well-known sequence
|
||||
let mut pt_pos = 64;
|
||||
let mut flipword: [u8; 4] = [0; 4];
|
||||
for word in first_block[64..].chunks_exact(4).into_iter() {
|
||||
bitflip(&word[0..4], &mut flipword);
|
||||
cwd = u32::from_be_bytes(flipword);
|
||||
pt_pos += 4;
|
||||
if (cwd & 0xE000_0000) == 0x4000_0000 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
oracle.type2_count = cwd & 0x3FF_FFFF;
|
||||
if pt_pos > 1000 { // pt_pos is usually found within the first 200 bytes of a bitstream, should definitely be in the first 1k or else shenanigans
|
||||
log::error!("type 2 region not found in the expected region, is the FPGA key correct?");
|
||||
return Err(RootkeyResult::KeyError)
|
||||
}
|
||||
oracle.type2_absolute_offset = pt_pos + ciphertext_start;
|
||||
oracle.type2_ciphertext_offset = pt_pos;
|
||||
log::info!("type2 absolute: {}, relative to ct start: {}", oracle.type2_absolute_offset, oracle.type2_ciphertext_offset);
|
||||
|
||||
Ok(oracle)
|
||||
}
|
||||
pub fn base(&self) -> u32 {self.base}
|
||||
pub fn ciphertext_offset(&self) -> usize {
|
||||
self.ct_absolute_offset as usize
|
||||
}
|
||||
pub fn ciphertext(&self) -> &[u8] {
|
||||
self.ciphertext
|
||||
}
|
||||
pub fn ciphertext_offset_to_frame(&self, offset: usize) -> (usize, usize) {
|
||||
let type2_offset = offset - self.type2_ciphertext_offset;
|
||||
|
||||
let frame = type2_offset / (101 * 4);
|
||||
let frame_offset = type2_offset - (frame * 101 * 4);
|
||||
(frame, frame_offset / 4)
|
||||
}
|
||||
pub fn clear(&mut self) {
|
||||
self.cipher.clear();
|
||||
self.enc_cipher.clear();
|
||||
self.dec_cipher.clear();
|
||||
}
|
||||
/// decrypts a portion of the bitstream starting at "from", of length output
|
||||
pub fn decrypt(&self, from: usize, output: &mut [u8]) {
|
||||
/// Decrypts a portion of the bitstream starting at "from", of length output.
|
||||
/// Returns the actual number of bytes processed.
|
||||
pub fn decrypt(&self, from: usize, output: &mut [u8]) -> usize {
|
||||
assert!(from & (AES_BLOCKSIZE - 1) == 0); // all requests must be an even multiple of an AES block size
|
||||
|
||||
let mut index = from;
|
||||
let mut temp_block = [0; AES_BLOCKSIZE];
|
||||
let mut chain: [u8; AES_BLOCKSIZE] = [0; AES_BLOCKSIZE];
|
||||
let mut bytes_processed = 0;
|
||||
for block in output.chunks_mut(AES_BLOCKSIZE).into_iter() {
|
||||
if index > self.ciphertext_len() - AES_BLOCKSIZE {
|
||||
return bytes_processed;
|
||||
}
|
||||
if index == 0 {
|
||||
chain = self.iv;
|
||||
} else {
|
||||
|
|
@ -195,7 +268,7 @@ impl<'a> BitstreamOracle<'a> {
|
|||
|
||||
// replaces the ciphertext with "plaintext"
|
||||
let mut d = GenericArray::clone_from_slice(&mut temp_block);
|
||||
self.cipher.decrypt_block(&mut d);
|
||||
self.dec_cipher.decrypt_block(&mut d);
|
||||
for (&src, dst) in d.iter().zip(temp_block.iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
|
|
@ -207,28 +280,106 @@ impl<'a> BitstreamOracle<'a> {
|
|||
*dst = src ^ iv;
|
||||
}
|
||||
index += AES_BLOCKSIZE;
|
||||
bytes_processed += AES_BLOCKSIZE;
|
||||
}
|
||||
bytes_processed
|
||||
}
|
||||
/// Encrypts a portion of a bitstream starting at "from"; manages the IV lookup for the encryption process
|
||||
///
|
||||
/// "from" is relative to ciphertext start, and chosen to match the "from" of a decrypt operation.
|
||||
/// When using this function to encrypt the very first block, the "from" offset should be negative.
|
||||
///
|
||||
/// ASSUME: the chain is unbroken, e.g. this is being called successively on correctly encrypted, chained
|
||||
/// blocks, that have been written to FLASH such that we can refer to the older blocks for the current
|
||||
/// chaining value. It is up to the caller to manage the linear order of the calls.
|
||||
/// ASSUME: `from` + `self.ct_absolute_offset` is a multiple of an erase block
|
||||
/// returns the actual number of bytes processed
|
||||
pub fn encrypt_sector(&self, from: i32, input_plaintext: &[u8], output_sector: &mut [u8]) -> usize {
|
||||
assert!(output_sector.len() & (AES_BLOCKSIZE - 1) == 0, "output length must be a multiple of AES block size");
|
||||
assert!(input_plaintext.len() & (AES_BLOCKSIZE - 1) == 0, "input length must be a multiple of AES block size");
|
||||
assert!((from + self.ct_absolute_offset as i32) & (spinor::SPINOR_ERASE_SIZE as i32 - 1) == 0, "request address must line up with an erase block boundary");
|
||||
|
||||
if from > 0 {
|
||||
assert!(input_plaintext.len() == output_sector.len(), "input and output length must match");
|
||||
} else {
|
||||
assert!(input_plaintext.len() == output_sector.len() - self.ct_absolute_offset, "output length must have space for the plaintext header");
|
||||
}
|
||||
|
||||
let mut out_start_offset = 0;
|
||||
if from < 0 {
|
||||
// copy the plaintext header as-is: we don't modify it, once it's in the device (e.g. we won't switch
|
||||
// from eFuse to BBRAM or back again). Later on if such a switching is desired, I believe it's just a couple
|
||||
// bytes patched in the plaintext header to change this, but, for now, let's assume once you're on a given
|
||||
// encryption train, you're staying on it. BBRAM requires external provisioning anyways, and BBRAM users
|
||||
// would be using this feature because they don't trust eFuse. eFuse users can't switch to BBRAM without an
|
||||
// external programmer that would burn the key in the first place.
|
||||
// the plaintext header already has:
|
||||
// - all the fuse and config settings
|
||||
// - padding
|
||||
// - IV for cipher
|
||||
// - length of ciphertext region
|
||||
for (&src, dst) in self.bitstream[..self.ct_absolute_offset].iter()
|
||||
.zip(output_sector[..self.ct_absolute_offset].iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
out_start_offset = self.ct_absolute_offset;
|
||||
}
|
||||
let mut chain: [u8; AES_BLOCKSIZE] = self.iv;
|
||||
if from > 0 {
|
||||
bitflip(&self.ciphertext[from as usize - AES_BLOCKSIZE..from as usize], &mut chain);
|
||||
}
|
||||
|
||||
let mut bytes_processed = 0;
|
||||
let mut temp_block = [0; AES_BLOCKSIZE];
|
||||
for (iblock, oblock) in input_plaintext.chunks(AES_BLOCKSIZE).into_iter()
|
||||
.zip(output_sector[out_start_offset..].chunks_mut(AES_BLOCKSIZE).into_iter()) {
|
||||
// XOR against IV/chain value
|
||||
for (dst, (&src, &iv)) in temp_block.iter_mut().zip(iblock.iter().zip(chain.iter())) {
|
||||
*dst = src ^ iv;
|
||||
}
|
||||
let mut e = GenericArray::clone_from_slice(&mut temp_block);
|
||||
self.enc_cipher.encrypt_block(&mut e);
|
||||
for (&src, dst) in e.iter().zip(temp_block.iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
// redo the IV based on the previous output. no bitflipping of the IV.
|
||||
for (&src, dst) in temp_block.iter().zip(chain.iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
|
||||
// copy the ciphertext into the output block, with a bitflip
|
||||
bitflip(&temp_block, oblock);
|
||||
bytes_processed += AES_BLOCKSIZE;
|
||||
}
|
||||
bytes_processed
|
||||
}
|
||||
|
||||
pub fn ciphertext_len(&self) -> usize {
|
||||
self.ciphertext.len()
|
||||
}
|
||||
}
|
||||
/*
|
||||
impl<'a> Drop for BitstreamOracle<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.cipher.clear();
|
||||
self.enc_cipher.clear();
|
||||
self.dec_cipher.clear();
|
||||
for b in self.iv.iter_mut() {
|
||||
*b = 0;
|
||||
}
|
||||
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
pub(crate) struct RootKeys {
|
||||
keyrom: utralib::CSR<u32>,
|
||||
gateware: xous::MemoryRange,
|
||||
staging: xous::MemoryRange,
|
||||
loader_code: xous::MemoryRange,
|
||||
kernel: xous::MemoryRange,
|
||||
gateware_mr: xous::MemoryRange,
|
||||
gateware_base: u32,
|
||||
staging_mr: xous::MemoryRange,
|
||||
staging_base: u32,
|
||||
loader_code_mr: xous::MemoryRange,
|
||||
loader_code_base: u32,
|
||||
kernel_mr: xous::MemoryRange,
|
||||
kernel_base: u32,
|
||||
/// regions of RAM that holds all plaintext passwords, keys, and temp data. stuck in two well-defined page so we can
|
||||
/// zero-ize it upon demand, without guessing about stack frames and/or Rust optimizers removing writes
|
||||
sensitive_data: xous::MemoryRange, // this gets purged at least on every suspend, but ideally purged sooner than that
|
||||
|
|
@ -238,10 +389,10 @@ pub(crate) struct RootKeys {
|
|||
cur_password_type: Option<PasswordType>, // for tracking which password we're dealing with at the UX layer
|
||||
susres: susres::Susres, // for disabling suspend/resume
|
||||
trng: trng::Trng,
|
||||
gam: gam::Gam, // for raising UX elements directly
|
||||
//gam: gam::Gam, // for raising UX elements directly
|
||||
gfx: graphics_server::Gfx, // for reading out font planes for signing verification
|
||||
spinor: spinor::Spinor,
|
||||
ticktimer: ticktimer_server::Ticktimer,
|
||||
//ticktimer: ticktimer_server::Ticktimer,
|
||||
}
|
||||
|
||||
impl RootKeys {
|
||||
|
|
@ -298,10 +449,14 @@ impl RootKeys {
|
|||
|
||||
let keys = RootKeys {
|
||||
keyrom: CSR::new(keyrom.as_mut_ptr() as *mut u32),
|
||||
gateware,
|
||||
staging,
|
||||
loader_code,
|
||||
kernel,
|
||||
gateware_mr: gateware,
|
||||
gateware_base: xous::SOC_MAIN_GW_LOC,
|
||||
staging_mr: staging,
|
||||
staging_base: xous::SOC_STAGING_GW_LOC,
|
||||
loader_code_mr: loader_code,
|
||||
loader_code_base: xous::LOADER_LOC,
|
||||
kernel_mr: kernel,
|
||||
kernel_base: xous::KERNEL_LOC,
|
||||
sensitive_data,
|
||||
pass_cache,
|
||||
update_password_policy: PasswordRetentionPolicy::AlwaysPurge,
|
||||
|
|
@ -309,14 +464,30 @@ impl RootKeys {
|
|||
cur_password_type: None,
|
||||
susres: susres::Susres::new_without_hook(&xns).expect("couldn't connect to susres without hook"),
|
||||
trng: trng::Trng::new(&xns).expect("couldn't connect to TRNG server"),
|
||||
gam: gam::Gam::new(&xns).expect("couldn't connect to GAM"),
|
||||
//gam: gam::Gam::new(&xns).expect("couldn't connect to GAM"),
|
||||
gfx: graphics_server::Gfx::new(&xns).expect("couldn't connect to gfx"),
|
||||
spinor,
|
||||
ticktimer: ticktimer_server::Ticktimer::new().expect("couldn't connect to ticktimer"),
|
||||
//ticktimer: ticktimer_server::Ticktimer::new().expect("couldn't connect to ticktimer"),
|
||||
};
|
||||
|
||||
keys
|
||||
}
|
||||
pub fn gateware(&self) -> &[u8] {
|
||||
self.gateware_mr.as_slice::<u8>()
|
||||
}
|
||||
pub fn gateware_base(&self) -> u32 { self.gateware_base }
|
||||
pub fn staging(&self) -> &[u8] {
|
||||
self.staging_mr.as_slice::<u8>()
|
||||
}
|
||||
pub fn staging_base(&self) -> u32 { self.staging_base }
|
||||
pub fn loader_code(&self) -> &[u8] {
|
||||
self.loader_code_mr.as_slice::<u8>()
|
||||
}
|
||||
pub fn loader_base(&self) -> u32 { self.loader_code_base }
|
||||
pub fn kernel(&self) -> &[u8] {
|
||||
self.kernel_mr.as_slice::<u8>()
|
||||
}
|
||||
pub fn kernel_base(&self) -> u32 { self.kernel_base }
|
||||
|
||||
fn purge_password(&mut self, pw_type: PasswordType) {
|
||||
unsafe {
|
||||
|
|
@ -545,11 +716,49 @@ impl RootKeys {
|
|||
/// - get ready for a reboot
|
||||
/// - returns true if we should reboot (everything succeeded)
|
||||
/// - returns false if we had an error condition (don't reboot)
|
||||
pub fn do_key_init(&mut self, progress_modal: &mut Modal, progress_action: &mut Slider) -> bool {
|
||||
pub fn do_key_init(&mut self, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
|
||||
// kick the progress bar to indicate we've entered the routine
|
||||
update_progress(1, progress_modal, progress_action);
|
||||
|
||||
// get access to the pcache and generate a keypair
|
||||
let pcache: &mut PasswordCache = unsafe{&mut *(self.pass_cache.as_mut_ptr() as *mut PasswordCache)};
|
||||
let keypair: Keypair = Keypair::generate(&mut self.trng);
|
||||
|
||||
// encrypt the FPGA key using the update password. in an un-init system, it is provided to us in plaintext format
|
||||
// e.g. in the case that we're doing a BBRAM boot (eFuse flow would give us a 0's key and we'd later on set it)
|
||||
#[cfg(feature = "hazardous-debug")]
|
||||
self.debug_print_key(KeyRomLocs::FPGA_KEY as usize, 256, "FPGA key before encryption: ");
|
||||
{
|
||||
let sensitive_slice = self.sensitive_data.as_slice_mut::<u32>();
|
||||
// before we encrypt it, stash a copy in our password cache, as we'll need it later on to encrypt the bitstream
|
||||
for (word, key) in sensitive_slice[KeyRomLocs::FPGA_KEY as usize..KeyRomLocs::FPGA_KEY as usize + 256/(size_of::<u32>()*8)].iter()
|
||||
.zip(pcache.fpga_key.chunks_mut(4).into_iter()) {
|
||||
for (&s, d) in word.to_be_bytes().iter().zip(key.iter_mut()) {
|
||||
*d = s;
|
||||
}
|
||||
}
|
||||
pcache.fpga_key_valid = 1;
|
||||
|
||||
// now encrypt it in the staging area
|
||||
for (word, key_word) in sensitive_slice[KeyRomLocs::FPGA_KEY as usize..KeyRomLocs::FPGA_KEY as usize + 256/(size_of::<u32>()*8)].iter_mut()
|
||||
.zip(pcache.hashed_update_pw.chunks(4).into_iter()) {
|
||||
*word = *word ^ u32::from_be_bytes(key_word.try_into().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
// allocate a decryption oracle for the FPGA bitstream. This will fail early if the FPGA key is wrong.
|
||||
assert!(pcache.fpga_key_valid == 1);
|
||||
// note to self: BitstreamOracle implements Drop which will clear the key schedule and iv
|
||||
let mut dst_oracle = match BitstreamOracle::new(&pcache.fpga_key, &pcache.fpga_key, self.gateware(), self.gateware_base()) {
|
||||
Ok(o) => o,
|
||||
Err(e) => {
|
||||
log::error!("couldn't create oracle (most likely FPGA key mismatch): {:?}", e);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
update_progress(5, progress_modal, progress_action);
|
||||
|
||||
// pub key is easy, no need to encrypt
|
||||
let public_key: [u8; ed25519_dalek::PUBLIC_KEY_LENGTH] = keypair.public.to_bytes();
|
||||
{ // scope sensitive_slice narrowly, as it borrows *self mutably, and can mess up later calls that borrow an immutable self
|
||||
|
|
@ -562,7 +771,6 @@ impl RootKeys {
|
|||
}
|
||||
|
||||
// extract the update password key from the cache, and apply it to the private key
|
||||
let pcache: &mut PasswordCache = unsafe{&mut *(self.pass_cache.as_mut_ptr() as *mut PasswordCache)};
|
||||
#[cfg(feature = "hazardous-debug")]
|
||||
{
|
||||
log::info!("cached boot passwords {:x?}", pcache.hashed_boot_pw);
|
||||
|
|
@ -587,7 +795,7 @@ impl RootKeys {
|
|||
}
|
||||
}
|
||||
|
||||
update_progress(5, progress_modal, progress_action);
|
||||
update_progress(10, progress_modal, progress_action);
|
||||
|
||||
// generate and store a root key (aka boot key), this is what is unlocked by the "boot password"
|
||||
// ironically, it's a "lower security" key because it just acts as a gatekeeper to further
|
||||
|
|
@ -619,7 +827,7 @@ impl RootKeys {
|
|||
|
||||
// sign the loader
|
||||
progress_modal.modify(None, Some(t!("rootkeys.init.signing_loader", xous::LANG)), false, None, false, None);
|
||||
update_progress(10, progress_modal, progress_action);
|
||||
update_progress(15, progress_modal, progress_action);
|
||||
let (loader_sig, loader_len) = self.sign_loader(&keypair);
|
||||
|
||||
// sign the kernel
|
||||
|
|
@ -628,34 +836,10 @@ impl RootKeys {
|
|||
let (kernel_sig, kernel_len) = self.sign_kernel(&keypair);
|
||||
|
||||
update_progress(25, progress_modal, progress_action);
|
||||
// encrypt the FPGA key using the update password. in an un-init system, it is provided to us in plaintext format
|
||||
// e.g. in the case that we're doing a BBRAM boot (eFuse flow would give us a 0's key and we'd later on set it)
|
||||
#[cfg(feature = "hazardous-debug")]
|
||||
self.debug_print_key(KeyRomLocs::FPGA_KEY as usize, 256, "FPGA key before encryption: ");
|
||||
{
|
||||
let sensitive_slice = self.sensitive_data.as_slice_mut::<u32>();
|
||||
// before we encrypt it, stash a copy in our password cache, as we'll need it later on to encrypt the bitstream
|
||||
for (word, key) in sensitive_slice[KeyRomLocs::FPGA_KEY as usize..KeyRomLocs::FPGA_KEY as usize + 256/(size_of::<u32>()*8)].iter()
|
||||
.zip(pcache.fpga_key.chunks_mut(4).into_iter()) {
|
||||
for (&s, d) in word.to_be_bytes().iter().zip(key.iter_mut()) {
|
||||
*d = s;
|
||||
}
|
||||
}
|
||||
pcache.fpga_key_valid = 1;
|
||||
|
||||
// now encrypt it in the staging area
|
||||
for (word, key_word) in sensitive_slice[KeyRomLocs::FPGA_KEY as usize..KeyRomLocs::FPGA_KEY as usize + 256/(size_of::<u32>()*8)].iter_mut()
|
||||
.zip(pcache.hashed_update_pw.chunks(4).into_iter()) {
|
||||
*word = *word ^ u32::from_be_bytes(key_word.try_into().unwrap());
|
||||
}
|
||||
}
|
||||
update_progress(30, progress_modal, progress_action);
|
||||
|
||||
// set the "init" bit in the staging area
|
||||
{
|
||||
let sensitive_slice = self.sensitive_data.as_slice_mut::<u32>();
|
||||
self.keyrom.wfo(utra::keyrom::ADDRESS_ADDRESS, KeyRomLocs::CONFIG as u32);
|
||||
let config = self.keyrom.rf(utra::keyrom::DATA_DATA);
|
||||
sensitive_slice[KeyRomLocs::CONFIG as usize] |= keyrom_config::INITIALIZED.ms(1);
|
||||
}
|
||||
|
||||
|
|
@ -670,43 +854,53 @@ impl RootKeys {
|
|||
// the staging area. Note that if we're doing an update, the update target would already be
|
||||
// in the staging area, so this step should be skipped.
|
||||
progress_modal.modify(None, Some(t!("rootkeys.init.backup_gateware", xous::LANG)), false, None, false, None);
|
||||
update_progress(40, progress_modal, progress_action);
|
||||
if self.make_gateware_backup(40, 60, progress_modal, progress_action).is_err() {
|
||||
log::error!("error occured in make_gateware_backup.");
|
||||
return false;
|
||||
update_progress(30, progress_modal, progress_action);
|
||||
self.make_gateware_backup(30, 50, progress_modal, progress_action)?;
|
||||
|
||||
let mut src_oracle = match BitstreamOracle::new(&pcache.fpga_key, &pcache.fpga_key, self.staging(), self.staging_base()) {
|
||||
Ok(o) => o,
|
||||
Err(e) => {
|
||||
log::error!("couldn't create oracle (most likely FPGA key mismatch): {:?}", e);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
// compute the keyrom patch set for the bitstream
|
||||
// at this point the KEYROM as replicated in sensitive_slice should have all its assets in place
|
||||
progress_modal.modify(None, Some(t!("rootkeys.init.patching_keys", xous::LANG)), false, None, false, None);
|
||||
update_progress(60, progress_modal, progress_action);
|
||||
update_progress(50, progress_modal, progress_action);
|
||||
|
||||
let gateware = self.gateware.as_slice::<u8>();
|
||||
assert!(pcache.fpga_key_valid == 1);
|
||||
// note to self: BitstreamOracle implements Drop which will clear the key schedule and iv
|
||||
let oracle = BitstreamOracle::new(&pcache.fpga_key, gateware);
|
||||
|
||||
if self.patch_keys(&oracle, 60, 70, progress_modal, progress_action).is_err() {
|
||||
log::error!("error occured in patch_keys.");
|
||||
return false;
|
||||
}
|
||||
patch::should_patch(42);
|
||||
self.gateware_copy_and_patch(&src_oracle, &dst_oracle, 50, 70, progress_modal, progress_action)?;
|
||||
|
||||
// verify that the patch worked
|
||||
progress_modal.modify(None, Some(t!("rootkeys.init.verifying_gateware", xous::LANG)), false, None, false, None);
|
||||
self.verify_gateware(&dst_oracle, 70, 90, progress_modal, progress_action)?;
|
||||
update_progress(90, progress_modal, progress_action);
|
||||
|
||||
// --> put the verify call here
|
||||
|
||||
// sign the image, commit the signature
|
||||
// --> add something to sign the gateware region here
|
||||
// --> format the signatures and write them to FLASH
|
||||
//////// this is 90%-100% task
|
||||
|
||||
// these implement drop so they should implicitly clear, but -- doesn't hurt to call it explicitly
|
||||
src_oracle.clear();
|
||||
dst_oracle.clear();
|
||||
|
||||
// finalize the progress bar on exit -- always leave at 100%
|
||||
progress_modal.modify(None, Some(t!("rootkeys.init.finished", xous::LANG)), false, None, false, None);
|
||||
update_progress(100, progress_modal, progress_action);
|
||||
|
||||
true
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn printkeys(&mut self) {
|
||||
// setup the local cache
|
||||
let sensitive_slice = self.sensitive_data.as_slice_mut::<u32>();
|
||||
for addr in 0..256 {
|
||||
self.keyrom.wfo(utra::keyrom::ADDRESS_ADDRESS, addr);
|
||||
sensitive_slice[addr as usize] = self.keyrom.rf(utra::keyrom::DATA_DATA);
|
||||
log::info!("{:02x}: 0x{:08x}", addr, sensitive_slice[addr as usize]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test(&mut self, progress_modal: &mut Modal, progress_action: &mut Slider) -> bool {
|
||||
|
|
@ -717,6 +911,7 @@ impl RootKeys {
|
|||
for addr in 0..256 {
|
||||
self.keyrom.wfo(utra::keyrom::ADDRESS_ADDRESS, addr);
|
||||
sensitive_slice[addr as usize] = self.keyrom.rf(utra::keyrom::DATA_DATA);
|
||||
log::info!("{:02x}: 0x{:08x}", addr, sensitive_slice[addr as usize]);
|
||||
}
|
||||
|
||||
for (word, key) in sensitive_slice[KeyRomLocs::FPGA_KEY as usize..KeyRomLocs::FPGA_KEY as usize + 256/(size_of::<u32>()*8)].iter()
|
||||
|
|
@ -726,19 +921,36 @@ impl RootKeys {
|
|||
}
|
||||
}
|
||||
pcache.fpga_key_valid = 1;
|
||||
sensitive_slice[KeyRomLocs::CONFIG as usize] |= keyrom_config::INITIALIZED.ms(1);
|
||||
sensitive_slice[0x30] = 0xc0de_600d;
|
||||
sensitive_slice[0x31] = 0x1234_5678;
|
||||
sensitive_slice[0x32] = 0x8000_0000;
|
||||
sensitive_slice[0x33] = 0x5555_3333;
|
||||
|
||||
// make the oracle
|
||||
let gateware = self.gateware.as_slice::<u8>();
|
||||
// one time only
|
||||
/*
|
||||
match self.make_gateware_backup(30, 50, progress_modal, progress_action) {
|
||||
Err(e) => {
|
||||
log::error!("got spinor error: {:?}", e);
|
||||
panic!("got spinor error, halting");
|
||||
}
|
||||
_ => ()
|
||||
};*/
|
||||
|
||||
// make the oracles
|
||||
assert!(pcache.fpga_key_valid == 1);
|
||||
let oracle = BitstreamOracle::new(&pcache.fpga_key, gateware);
|
||||
// copy from staging
|
||||
let src_oracle = BitstreamOracle::new(&pcache.fpga_key, &pcache.fpga_key, self.staging(), self.staging_base()).unwrap();
|
||||
// write to gateware
|
||||
let dst_oracle = BitstreamOracle::new(&pcache.fpga_key, &pcache.fpga_key, self.gateware(), self.gateware_base()).unwrap();
|
||||
|
||||
// TEST
|
||||
if self.patch_keys(&oracle, 60, 80, progress_modal, progress_action).is_err() {
|
||||
if self.gateware_copy_and_patch(&src_oracle, &dst_oracle, 60, 80, progress_modal, progress_action).is_err() {
|
||||
log::error!("error occured in patch_keys.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if self.verify_gateware(&oracle, 80, 100, progress_modal, progress_action).is_err() {
|
||||
if self.verify_gateware(&dst_oracle, 80, 100, progress_modal, progress_action).is_err() {
|
||||
log::error!("error occurred in gateware verification");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -748,34 +960,233 @@ impl RootKeys {
|
|||
true
|
||||
}
|
||||
|
||||
fn patch_keys(&self, oracle: &BitstreamOracle, prog_start: u32, prog_end: u32, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
|
||||
/// copy data from a source region to a destination region, re-encrypting and patching as we go along.
|
||||
/// the region/region_base should be specified for the destination oracle
|
||||
///
|
||||
/// KEYROM patching data must previously have been staged in the sensitive area.
|
||||
/// failure to do so would result in the erasure of all secret data.
|
||||
/// ASSUME: CSR appendix does not change during the copy (it is not copied/updated)
|
||||
fn gateware_copy_and_patch(&self, src_oracle: &BitstreamOracle, dst_oracle: &BitstreamOracle,
|
||||
prog_start: u32, prog_end: u32, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
|
||||
let mut last_prog_update = 0;
|
||||
|
||||
// extract the HMAC header
|
||||
let mut hmac_header: [u8; 64] = [0; 64];
|
||||
oracle.decrypt(0, &mut hmac_header);
|
||||
|
||||
// check that the header has a well-known sequence in it -- sanity check the AES key
|
||||
let mut pass = true;
|
||||
for &b in hmac_header[32..].iter() {
|
||||
if b != 0x6C {
|
||||
pass = false;
|
||||
}
|
||||
}
|
||||
if !pass {
|
||||
log::error!("hmac_header did not decrypt correctly: {:x?}", hmac_header);
|
||||
let sensitive_slice = self.sensitive_data.as_slice_mut::<u32>();
|
||||
if sensitive_slice[KeyRomLocs::CONFIG as usize] & keyrom_config::INITIALIZED.ms(1) == 0 {
|
||||
// the keys weren't initialized, or are wrong. abort!
|
||||
return Err(RootkeyResult::KeyError);
|
||||
}
|
||||
log::info!("sanity checks: src_offset {}, dst_offset {}, src_len {}, dst_len {}",
|
||||
src_oracle.ciphertext_offset(), dst_oracle.ciphertext_offset(), src_oracle.ciphertext_len(), dst_oracle.ciphertext_len());
|
||||
|
||||
// patch the keyrom frames
|
||||
for frame in patch::PATCH_FRAMES.iter() {
|
||||
// start with a naive implementation that simple goes through and re-encrypts and patches everything.
|
||||
// later on, we could skip patching everything up to the first frame that needs patching;
|
||||
// this should optimize up to 15% of the time required to do a patch, although, because the patching
|
||||
// routine is "smart" and does not issue writes for unchanged data, this could actually be a much
|
||||
// smaller performance gain.
|
||||
|
||||
let mut pt_sector: [u8; spinor::SPINOR_ERASE_SIZE as usize] = [0; spinor::SPINOR_ERASE_SIZE as usize];
|
||||
let mut ct_sector: [u8; spinor::SPINOR_ERASE_SIZE as usize] = [0; spinor::SPINOR_ERASE_SIZE as usize];
|
||||
let mut flipper: [u8; spinor::SPINOR_ERASE_SIZE as usize] = [0; spinor::SPINOR_ERASE_SIZE as usize];
|
||||
|
||||
let mut hasher = engine_sha512::Sha256::new();
|
||||
let hash_stop = src_oracle.ciphertext_len() - 320 - 160;
|
||||
|
||||
// handle the special case of the first sector
|
||||
src_oracle.decrypt(0, &mut pt_sector);
|
||||
|
||||
// initialize the hmac code for later use
|
||||
let mut hmac_code: [u8; 32] = [0; 32];
|
||||
for (dst, (&hm1, &mask)) in
|
||||
hmac_code.iter_mut()
|
||||
.zip(pt_sector[0..32].iter().zip(pt_sector[32..64].iter())) {
|
||||
*dst = hm1 ^ mask;
|
||||
}
|
||||
log::info!("recovered hmac: {:x?}", hmac_code);
|
||||
// hash the decrypt data; we assume we're not patching anything in the first sector.
|
||||
let mut bytes_hashed = spinor::SPINOR_ERASE_SIZE as usize - src_oracle.ciphertext_offset();
|
||||
bitflip(&pt_sector[..bytes_hashed], &mut flipper[..bytes_hashed]);
|
||||
hasher.update(&flipper[..bytes_hashed]);
|
||||
|
||||
// now encrypt and patch the data to disk
|
||||
dst_oracle.encrypt_sector(
|
||||
-(dst_oracle.ciphertext_offset() as i32),
|
||||
&pt_sector[..bytes_hashed],
|
||||
&mut ct_sector // full array, for space for plaintext header
|
||||
);
|
||||
log::info!("sector 0 patch len: {}", bytes_hashed);
|
||||
self.spinor.patch(dst_oracle.bitstream, dst_oracle.base, &ct_sector, 0)
|
||||
.map_err(|_| RootkeyResult::FlashError)?;
|
||||
|
||||
// now we can patch the rest of the sectors as a loop
|
||||
let mut from = spinor::SPINOR_ERASE_SIZE - src_oracle.ciphertext_offset() as u32;
|
||||
let mut dummy_consume = 0;
|
||||
let max_step = src_oracle.ciphertext[from as usize..].chunks(spinor::SPINOR_ERASE_SIZE as usize).into_iter().count();
|
||||
for (step, _) in src_oracle.ciphertext[from as usize..].chunks(spinor::SPINOR_ERASE_SIZE as usize).into_iter().enumerate() {
|
||||
let decrypt_len = src_oracle.decrypt(from as usize, &mut pt_sector);
|
||||
|
||||
// wrap the patch call with a range check, because the patch lookup search is pretty expensive
|
||||
if self.patch_in_range(src_oracle, from, from + spinor::SPINOR_ERASE_SIZE as u32) {
|
||||
dummy_consume ^= self.patch_sector(src_oracle, from, &mut pt_sector, &sensitive_slice[0..256]);
|
||||
}
|
||||
|
||||
let hash_len = if bytes_hashed + decrypt_len < hash_stop {
|
||||
decrypt_len
|
||||
} else {
|
||||
hash_stop - bytes_hashed
|
||||
};
|
||||
if hash_len > 0 {
|
||||
bitflip(&pt_sector[..hash_len], &mut flipper[..hash_len]);
|
||||
hasher.update(&flipper[..hash_len]);
|
||||
bytes_hashed += hash_len;
|
||||
if hash_len != decrypt_len {
|
||||
log::info!("final short block len: {}", hash_len);
|
||||
}
|
||||
}
|
||||
|
||||
dst_oracle.encrypt_sector(
|
||||
from as i32,
|
||||
&pt_sector[..decrypt_len],
|
||||
&mut ct_sector[..decrypt_len],
|
||||
);
|
||||
self.spinor.patch(dst_oracle.bitstream, dst_oracle.base,
|
||||
&ct_sector[..decrypt_len], from + dst_oracle.ciphertext_offset() as u32)
|
||||
.map_err(|_| RootkeyResult::FlashError)?;
|
||||
|
||||
from += decrypt_len as u32;
|
||||
let progress = ((prog_end - prog_start) * step as u32) / max_step as u32;
|
||||
if progress != last_prog_update {
|
||||
last_prog_update = progress;
|
||||
update_progress(progress + prog_start, progress_modal, progress_action);
|
||||
}
|
||||
}
|
||||
// consume the dummy value, to ensure it's not optimized out by the compiler
|
||||
log::info!("copy_and_patch dummy consume: 0x{:x}", dummy_consume);
|
||||
|
||||
|
||||
// at this point, we've patched & encrypted all the sectors, but we've
|
||||
// encrypted the wrong hash at the end, so the HMAC won't work out. let's patch that.
|
||||
let h1_digest: [u8; 32] = hasher.finalize().try_into().unwrap();
|
||||
log::info!("bytes hashed: {}, computed h1 hash: {:x?}", bytes_hashed, h1_digest);
|
||||
|
||||
let mut hasher2 = engine_sha512::Sha256::new();
|
||||
let footer_mask: [u8; 32] = [0x3A; 32];
|
||||
let mut masked_footer: [u8; 32] = [0; 32];
|
||||
for (dst, (&hm2, &mask)) in
|
||||
masked_footer.iter_mut()
|
||||
.zip(hmac_code.iter().zip(footer_mask.iter())) {
|
||||
*dst = hm2 ^ mask;
|
||||
}
|
||||
log::info!("masked_footer: {:x?}", masked_footer);
|
||||
log::info!("footer_mask: {:x?}", footer_mask);
|
||||
let mut masked_footer_flipped: [u8; 32] = [0; 32];
|
||||
bitflip(&masked_footer, &mut masked_footer_flipped);
|
||||
let mut footer_mask_flipped: [u8; 32] = [0; 32];
|
||||
bitflip(&footer_mask, &mut footer_mask_flipped);
|
||||
hasher2.update(masked_footer_flipped);
|
||||
hasher2.update(footer_mask_flipped);
|
||||
hasher2.update(h1_digest);
|
||||
let h2_digest: [u8; 32] = hasher2.finalize().try_into().unwrap();
|
||||
log::info!("h2 hash: {:x?}", h2_digest);
|
||||
|
||||
// now encrypt and patch this final hashed value into the expected area
|
||||
let ct_end = dst_oracle.ciphertext_len();
|
||||
|
||||
// the math below will have some problems if the block happens to end up exactly on an erase block boundary.
|
||||
// but it doesn't, so I'm going to leave that case unaddressed...
|
||||
let ct_last_block_loc = (ct_end & !(spinor::SPINOR_ERASE_SIZE as usize - 1)) - dst_oracle.ciphertext_offset();
|
||||
let pt_sector_len = ct_end - ct_last_block_loc;
|
||||
|
||||
log::info!("ct_end: {}, ct_last_block_loc {}, pt_sector_len {}", ct_end, ct_last_block_loc, pt_sector_len);
|
||||
src_oracle.decrypt(ct_last_block_loc, &mut pt_sector[..pt_sector_len]);
|
||||
let mut temp = ct_last_block_loc;
|
||||
for block in pt_sector[..pt_sector_len].chunks(32).into_iter() {
|
||||
log::info!("{:x}: {:x?}", temp, block);
|
||||
temp += 32;
|
||||
}
|
||||
//log::info!("last bytes: {:x?}", &pt_sector[pt_sector_len-256..pt_sector_len]);
|
||||
|
||||
// patch in the hash at the very end
|
||||
let mut h2_digest_flipped: [u8; 32] = [0; 32];
|
||||
bitflip(&h2_digest, &mut h2_digest_flipped);
|
||||
for (&src, dst) in h2_digest_flipped.iter()
|
||||
.zip(pt_sector[pt_sector_len - 32..pt_sector_len].iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
log::info!("last bytes patched: {:x?}", &pt_sector[pt_sector_len-256..pt_sector_len]);
|
||||
|
||||
dst_oracle.encrypt_sector(ct_last_block_loc as i32, &pt_sector[..pt_sector_len], &mut ct_sector[..pt_sector_len]);
|
||||
log::info!("hash patching from 0x{:x} len {}", ct_last_block_loc, pt_sector_len);
|
||||
self.spinor.patch(dst_oracle.bitstream, dst_oracle.base,
|
||||
&ct_sector[..pt_sector_len], ct_last_block_loc as u32 + dst_oracle.ciphertext_offset() as u32)
|
||||
.map_err(|_| RootkeyResult::FlashError)?;
|
||||
|
||||
// read back for debug
|
||||
log::info!("debug readback");
|
||||
let dl = dst_oracle.decrypt(ct_last_block_loc, &mut pt_sector);
|
||||
let mut temp = ct_last_block_loc;
|
||||
for block in pt_sector[..dl].chunks(32).into_iter() {
|
||||
log::info!("{:x}: {:x?}", temp, block);
|
||||
temp += 32;
|
||||
}
|
||||
log::info!("dl: {} tl: {}", dl, dst_oracle.ciphertext_len());
|
||||
|
||||
let dl = dst_oracle.decrypt(0, &mut pt_sector);
|
||||
let mut temp = 0;
|
||||
for block in pt_sector[..dl].chunks(32).into_iter() {
|
||||
log::info!("{:x}: {:x?}", temp, block);
|
||||
temp += 32;
|
||||
}
|
||||
let dl = dst_oracle.decrypt(4096, &mut pt_sector);
|
||||
let mut temp = 4096;
|
||||
for block in pt_sector[..dl].chunks(32).into_iter() {
|
||||
log::info!("{:x}: {:x?}", temp, block);
|
||||
temp += 32;
|
||||
}
|
||||
|
||||
// now seek to the various frames and patch their data...
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn patch_in_range(&self, oracle: &BitstreamOracle, range_ct_start: u32, range_ct_end: u32) -> bool {
|
||||
let (start_frame, _) = oracle.ciphertext_offset_to_frame(range_ct_start as usize);
|
||||
let (end_frame, _) = oracle.ciphertext_offset_to_frame(range_ct_end as usize);
|
||||
|
||||
if end_frame < patch::PATCH_FRAMES[0] as usize || start_frame > *patch::PATCH_FRAMES.last().unwrap() as usize {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
// data_ct_start is the ciphertext offset of the region we're searching for a patch in
|
||||
fn patch_sector(&self, oracle: &BitstreamOracle, data_ct_start: u32, data: &mut [u8], keyrom: &[u32]) -> u32 {
|
||||
assert!(keyrom.len() == 256, "KEYROM data is not whole");
|
||||
|
||||
let mut dummy_consume = 0;
|
||||
for (offset, word) in data.chunks_mut(4).into_iter().enumerate() {
|
||||
let ct_offset = data_ct_start as usize + offset * 4;
|
||||
let (frame, frame_offset) = oracle.ciphertext_offset_to_frame(ct_offset);
|
||||
|
||||
// the outer should_patch() call is a small optimization that replaces an O(N) search through
|
||||
// a frame array with a pair of limit comparisons.
|
||||
if patch::should_patch(frame as u32) {
|
||||
match patch::patch_frame(frame as u32, frame_offset as u32, keyrom) {
|
||||
Some((patch, patch_inv)) => {
|
||||
let mut flip: [u8; 4] = [0; 4];
|
||||
bitflip(&patch.to_be_bytes(), &mut flip);
|
||||
log::info!("patching {} frame 0x{:x} offset {} 0x{:x} -> 0x{:x}", ct_offset, frame, frame_offset,
|
||||
u32::from_be_bytes(word[0..4].try_into().unwrap()), u32::from_be_bytes(flip));
|
||||
for (&s, d) in flip.iter().zip(word.iter_mut()) {
|
||||
*d = s;
|
||||
}
|
||||
//log::info!("patched 0x{:x}", u32::from_be_bytes(word[0..4].try_into().unwrap()));
|
||||
dummy_consume ^= patch_inv; // consume the dummy value (to keep constant time properties)
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
dummy_consume
|
||||
}
|
||||
|
||||
fn verify_gateware(&self, oracle: &BitstreamOracle, prog_start: u32, prog_end: u32, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
|
||||
let mut last_prog_update = 0;
|
||||
|
||||
|
|
@ -787,7 +1198,7 @@ impl RootKeys {
|
|||
.zip(hmac_area[0..32].iter().zip(hmac_area[32..64].iter())) {
|
||||
*dst = hm1 ^ mask;
|
||||
}
|
||||
log::trace!("hmac code: {:x?}", hmac_code);
|
||||
log::info!("hmac code: {:x?}", hmac_code);
|
||||
|
||||
log::debug!("verifying gateware");
|
||||
let mut hasher = engine_sha512::Sha256::new();
|
||||
|
|
@ -812,7 +1223,7 @@ impl RootKeys {
|
|||
}
|
||||
}
|
||||
let h1_digest: [u8; 32] = hasher.finalize().try_into().unwrap();
|
||||
log::trace!("computed hash: {:x?}", h1_digest);
|
||||
log::info!("computed hash of {} bytes: {:x?}", tot_len, h1_digest);
|
||||
|
||||
let mut hasher2 = engine_sha512::Sha256::new();
|
||||
let footer_mask: [u8; 32] = [0x3A; 32];
|
||||
|
|
@ -822,8 +1233,8 @@ impl RootKeys {
|
|||
.zip(hmac_code.iter().zip(footer_mask.iter())) {
|
||||
*dst = hm2 ^ mask;
|
||||
}
|
||||
log::debug!("masked_footer: {:x?}", masked_footer);
|
||||
log::debug!("footer_mask: {:x?}", footer_mask);
|
||||
log::info!("masked_footer: {:x?}", masked_footer);
|
||||
log::info!("footer_mask: {:x?}", footer_mask);
|
||||
let mut masked_footer_flipped: [u8; 32] = [0; 32];
|
||||
bitflip(&masked_footer, &mut masked_footer_flipped);
|
||||
let mut footer_mask_flipped: [u8; 32] = [0; 32];
|
||||
|
|
@ -833,13 +1244,13 @@ impl RootKeys {
|
|||
hasher2.update(h1_digest);
|
||||
let h2_digest: [u8; 32] = hasher2.finalize().try_into().unwrap();
|
||||
|
||||
log::debug!("h2 hash: {:x?}", h2_digest);
|
||||
log::info!("h2 hash: {:x?}", h2_digest);
|
||||
let mut ref_digest_flipped: [u8; 32] = [0; 32];
|
||||
oracle.decrypt(oracle.ciphertext_len() - 32, &mut ref_digest_flipped);
|
||||
let mut ref_digest: [u8; 32] = [0; 32];
|
||||
log::debug!("ref digest (flipped): {:x?}", ref_digest_flipped);
|
||||
log::info!("ref digest (flipped): {:x?}", ref_digest_flipped);
|
||||
bitflip(&ref_digest_flipped, &mut ref_digest);
|
||||
log::debug!("ref digest : {:x?}", ref_digest);
|
||||
log::info!("ref digest : {:x?}", ref_digest);
|
||||
|
||||
let mut matching = true;
|
||||
for (&l, &r) in ref_digest.iter().zip(h2_digest.iter()) {
|
||||
|
|
@ -849,32 +1260,36 @@ impl RootKeys {
|
|||
}
|
||||
|
||||
if matching {
|
||||
log::info!("gateware verified");
|
||||
Ok(())
|
||||
} else {
|
||||
log::info!("gateware failed to verify");
|
||||
Err(RootkeyResult::IntegrityError)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn make_gateware_backup(&mut self, prog_start: u32, prog_end: u32, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
|
||||
let gateware_dest = self.staging.as_slice::<u8>();
|
||||
let gateware_src = self.gateware.as_slice::<u8>();
|
||||
fn make_gateware_backup(&self, prog_start: u32, prog_end: u32, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
|
||||
let gateware_dest = self.staging();
|
||||
let mut gateware_dest_base = self.staging_base();
|
||||
let gateware_src = self.gateware();
|
||||
|
||||
log::trace!("src: {:x?}", &gateware_src[0..32]);
|
||||
log::trace!("dst: {:x?}", &gateware_dest[0..32]);
|
||||
|
||||
let mut last_prog_update = 0;
|
||||
const PATCH_CHUNK: usize = 65536; // this controls the granularity of the erase operation
|
||||
let mut dest_patch_addr = xous::SOC_STAGING_GW_LOC;
|
||||
let mut prog_ctr = 0;
|
||||
for (dst, src) in
|
||||
gateware_dest.chunks(PATCH_CHUNK).into_iter()
|
||||
.zip(gateware_src.chunks(PATCH_CHUNK)) {
|
||||
log::debug!("writing {} backup bytes to address 0x{:08x}", src.len(), dest_patch_addr);
|
||||
self.spinor.patch(dst, dest_patch_addr, src, 0)
|
||||
log::debug!("writing {} backup bytes to offset 0x{:08x}", src.len(), prog_ctr);
|
||||
self.spinor.patch(dst, gateware_dest_base, src, 0)
|
||||
.map_err(|_| RootkeyResult::FlashError)?;
|
||||
dest_patch_addr += PATCH_CHUNK as u32;
|
||||
gateware_dest_base += PATCH_CHUNK as u32;
|
||||
|
||||
let progress = ((prog_end - prog_start) * (dest_patch_addr - xous::SOC_STAGING_GW_LOC)) / xous::SOC_STAGING_GW_LEN;
|
||||
prog_ctr += PATCH_CHUNK as u32;
|
||||
let progress = ((prog_end - prog_start) * prog_ctr) / xous::SOC_STAGING_GW_LEN;
|
||||
if progress != last_prog_update {
|
||||
last_prog_update = progress;
|
||||
update_progress(progress + prog_start, progress_modal, progress_action);
|
||||
|
|
@ -912,7 +1327,7 @@ impl RootKeys {
|
|||
log::info!("{}", debugstr);
|
||||
}
|
||||
|
||||
pub fn sign_loader(&mut self, signing_key: &Keypair) -> (Signature, u32) {
|
||||
pub fn sign_loader(&self, signing_key: &Keypair) -> (Signature, u32) {
|
||||
let loader_len =
|
||||
xous::LOADER_CODE_LEN
|
||||
- SIGBLOCK_SIZE
|
||||
|
|
@ -921,13 +1336,13 @@ impl RootKeys {
|
|||
|
||||
// this is a huge hash, so, get a hardware hasher, even if it means waiting for it
|
||||
let mut hasher = engine_sha512::Sha512::new(Some(engine_sha512::FallbackStrategy::WaitForHardware));
|
||||
let loader_region = self.loader_code.as_slice::<u8>();
|
||||
let loader_region = self.loader_code();
|
||||
// the loader data starts one page in; the first page is reserved for the signature itself
|
||||
hasher.update(&loader_region[SIGBLOCK_SIZE as usize..]);
|
||||
|
||||
// now get the font plane data
|
||||
self.gfx.bulk_read_restart(); // reset the bulk read pointers on the gfx side
|
||||
let mut bulkread = BulkRead::default();
|
||||
let bulkread = BulkRead::default();
|
||||
let mut buf = xous_ipc::Buffer::into_buf(bulkread).expect("couldn't transform bulkread into aligned buffer");
|
||||
// this form of loop was chosen to avoid the multiple re-initializations and copies that would be entailed
|
||||
// in our usual idiom for pasing buffers around. instead, we create a single buffer, and re-use it for
|
||||
|
|
@ -957,9 +1372,9 @@ impl RootKeys {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn sign_kernel(&mut self, signing_key: &Keypair) -> (Signature, u32) {
|
||||
pub fn sign_kernel(&self, signing_key: &Keypair) -> (Signature, u32) {
|
||||
let mut hasher = engine_sha512::Sha512::new(Some(engine_sha512::FallbackStrategy::WaitForHardware));
|
||||
let kernel_region = self.kernel.as_slice::<u8>();
|
||||
let kernel_region = self.kernel();
|
||||
// for the kernel length, we can't know/trust the given length in the signature field, so we sign the entire
|
||||
// length of the region. This will increase the time it takes to verify; however, at the current trend, we'll probably
|
||||
// use most of the available space for the kernel, so by the time we're done maybe only 10-20% of the space is empty.
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ pub struct PatchFrame {{
|
|||
/// returns a tuple of the value and its inverse; this is done to reduce the timing
|
||||
/// sidechannel. The inverse value needs to be consumed to prevent the compiler
|
||||
/// from optimizing out that path.
|
||||
pub fn patch_frame(frame: u32, offset: u32, rom: &[u32; 256]) -> (Option<u32>, Option<u32>) {{\n""".format(patchlen))
|
||||
pub fn patch_frame(frame: u32, offset: u32, rom: &[u32]) -> Option<(u32, u32)> {{\n""".format(patchlen))
|
||||
|
||||
for frame_rec in patchdata_sorted:
|
||||
frame = frame_rec[1]
|
||||
|
|
@ -448,13 +448,13 @@ pub fn patch_frame(frame: u32, offset: u32, rom: &[u32; 256]) -> (Option<u32>, O
|
|||
data_inv |= 1 << bit;
|
||||
}
|
||||
}
|
||||
return (Some(data), Some(data_inv))
|
||||
return Some((data, data_inv))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (None, None)
|
||||
return None
|
||||
}
|
||||
""")
|
||||
|
||||
|
|
@ -501,10 +501,10 @@ mod tests {
|
|||
bitvalue = (keyrom[coord[0]] & (1 << coord[1]))
|
||||
if bitvalue != 0:
|
||||
wordvalue |= (1 << bit)
|
||||
f.write(' assert_eq!(crate::patch_frame({}'.format(frame_rec[0]) + ', ' + '{}'.format(word) + ', ROM), (Some(' + '0x{:08x}'.format(wordvalue) + '), Some(!0x{:08x}'.format(wordvalue) + ')));\n')
|
||||
f.write(' assert_eq!(crate::patch_frame({}'.format(frame_rec[0]) + ', ' + '{}'.format(word) + ', &ROM), (Some(' + '0x{:08x}'.format(wordvalue) + '), Some(!0x{:08x}'.format(wordvalue) + ')));\n')
|
||||
|
||||
f.write(' // also test the null case, frame 0 should typically have no mappings.\n')
|
||||
f.write(' assert_eq!(crate::patch_frame(0x0, 0, ROM), (None, None) );\n')
|
||||
f.write(' assert_eq!(crate::patch_frame(0x0, 0, &ROM), (None, None) );\n')
|
||||
f.write("""
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1034
services/root-keys/src/key2bits/patch.rs
Normal file → Executable file
1034
services/root-keys/src/key2bits/patch.rs
Normal file → Executable file
File diff suppressed because it is too large
Load diff
|
|
@ -5,7 +5,6 @@ pub mod api;
|
|||
use api::*;
|
||||
|
||||
pub mod key2bits;
|
||||
use key2bits::*;
|
||||
|
||||
use xous::{CID, send_message, Message};
|
||||
use num_traits::*;
|
||||
|
|
@ -106,13 +105,13 @@ impl RootKeys {
|
|||
pub fn self_sign(&mut self, which: ImageType) -> Result<(), xous::Error> {
|
||||
unimplemented!();
|
||||
}
|
||||
/*
|
||||
|
||||
pub fn test_ux(&mut self, arg: usize) {
|
||||
send_message(self.conn,
|
||||
Message::new_scalar(Opcode::TestUx.to_usize().unwrap(),
|
||||
arg, 0, 0, 0)
|
||||
).expect("couldn't send test message");
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
mod api;
|
||||
use api::*;
|
||||
use xous::{CID, msg_scalar_unpack, send_message, Message, msg_blocking_scalar_unpack};
|
||||
use xous::{msg_scalar_unpack, send_message, msg_blocking_scalar_unpack};
|
||||
use xous_ipc::{String, Buffer};
|
||||
|
||||
use num_traits::*;
|
||||
|
|
@ -188,7 +188,7 @@ fn xmain() -> ! {
|
|||
|
||||
xous::yield_slice(); // give some time to the GAM to render
|
||||
|
||||
let success = keys.test(&mut rootkeys_modal, &mut progress_action);
|
||||
let _success = keys.test(&mut rootkeys_modal, &mut progress_action);
|
||||
} else {
|
||||
// overall flow:
|
||||
// - setup the init
|
||||
|
|
@ -217,6 +217,9 @@ fn xmain() -> ! {
|
|||
Some(ActionType::Notification(dismiss_modal_action)),
|
||||
Some(t!("rootkeys.setup", xous::LANG)), false,
|
||||
None, true, None);
|
||||
|
||||
////// insert the "are you sure" message at this point in the flow -- don't call setup_key_init() until we're confirmed!
|
||||
|
||||
// setup_key_init() prepares the salt and other items necessary to receive a password safely
|
||||
keys.setup_key_init();
|
||||
// request the boot password first
|
||||
|
|
@ -280,45 +283,74 @@ fn xmain() -> ! {
|
|||
xous::yield_slice(); // give some time to the GAM to render
|
||||
|
||||
// this routine will update the rootkeys_modal with the current Ux state
|
||||
let success = keys.do_key_init(&mut rootkeys_modal, &mut progress_action);
|
||||
let result = keys.do_key_init(&mut rootkeys_modal, &mut progress_action);
|
||||
|
||||
// the stop emoji, when sent to the slider action bar in progress mode, will cause it to close and relinquish focus
|
||||
rootkeys_modal.key_event(['🛑', '\u{0000}', '\u{0000}', '\u{0000}']);
|
||||
|
||||
// at this point, we may want to pop up a modal indicating we are going to reboot?
|
||||
// we also need to include a command that does the reboot.
|
||||
if success {
|
||||
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
|
||||
rootkeys_modal.modify(
|
||||
Some(ActionType::Notification(dismiss_modal_action)),
|
||||
Some(t!("rootkeys.init.finished", xous::LANG)), false,
|
||||
None, false, None);
|
||||
rootkeys_modal.activate();
|
||||
xous::yield_slice();
|
||||
match result {
|
||||
Ok(_) => {
|
||||
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
|
||||
rootkeys_modal.modify(
|
||||
Some(ActionType::Notification(dismiss_modal_action)),
|
||||
Some(t!("rootkeys.init.finished", xous::LANG)), false,
|
||||
None, false, None);
|
||||
rootkeys_modal.activate();
|
||||
xous::yield_slice();
|
||||
|
||||
// TODO: insert the reboot code here
|
||||
} else {
|
||||
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
|
||||
rootkeys_modal.modify(
|
||||
Some(ActionType::Notification(dismiss_modal_action)),
|
||||
Some(t!("rootkeys.init.failure", xous::LANG)), false,
|
||||
None, false, None);
|
||||
rootkeys_modal.activate();
|
||||
xous::yield_slice();
|
||||
// TODO: insert the reboot code here
|
||||
}
|
||||
Err(RootkeyResult::AlignmentError) => {
|
||||
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
|
||||
rootkeys_modal.modify(
|
||||
Some(ActionType::Notification(dismiss_modal_action)),
|
||||
Some(t!("rootkeys.init.fail_alignment", xous::LANG)), false,
|
||||
None, false, None);
|
||||
rootkeys_modal.activate();
|
||||
xous::yield_slice();
|
||||
}
|
||||
Err(RootkeyResult::KeyError) => {
|
||||
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
|
||||
rootkeys_modal.modify(
|
||||
Some(ActionType::Notification(dismiss_modal_action)),
|
||||
Some(t!("rootkeys.init.fail_key", xous::LANG)), false,
|
||||
None, false, None);
|
||||
rootkeys_modal.activate();
|
||||
xous::yield_slice();
|
||||
}
|
||||
Err(RootkeyResult::IntegrityError) => {
|
||||
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
|
||||
rootkeys_modal.modify(
|
||||
Some(ActionType::Notification(dismiss_modal_action)),
|
||||
Some(t!("rootkeys.init.fail_verify", xous::LANG)), false,
|
||||
None, false, None);
|
||||
rootkeys_modal.activate();
|
||||
xous::yield_slice();
|
||||
}
|
||||
Err(RootkeyResult::FlashError) => {
|
||||
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
|
||||
rootkeys_modal.modify(
|
||||
Some(ActionType::Notification(dismiss_modal_action)),
|
||||
Some(t!("rootkeys.init.fail_burn", xous::LANG)), false,
|
||||
None, false, None);
|
||||
rootkeys_modal.activate();
|
||||
xous::yield_slice();
|
||||
}
|
||||
}
|
||||
|
||||
// clear all the state, re-enable suspend/resume
|
||||
keys.finish_key_init();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::error!("invalid UX state -- someone called init password return, but no password type was set!");
|
||||
}
|
||||
},
|
||||
/*
|
||||
Some(Opcode::TestUx) => msg_scalar_unpack!(msg, arg, _, _, _, {
|
||||
log::debug!("activating password modal");
|
||||
keys.set_ux_password_type(PasswordType::Boot);
|
||||
rootkeys_modal.activate();
|
||||
//policy_menu.activate();
|
||||
}),*/
|
||||
keys.printkeys();
|
||||
}),
|
||||
Some(Opcode::UxGetPolicy) => {
|
||||
policy_menu.activate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,11 +50,11 @@ impl<'a> ShellCmdApi<'a> for Keys {
|
|||
|
||||
if let Some(sub_cmd) = tokens.next() {
|
||||
match sub_cmd {
|
||||
/*"ux" => {
|
||||
"ux" => {
|
||||
self.rootkeys.test_ux(0);
|
||||
//debug_here::debug_here!();
|
||||
write!(ret, "show UX").unwrap();
|
||||
}*/
|
||||
}
|
||||
"usblock" => {
|
||||
env.llio.debug_usb(Some(true)).unwrap();
|
||||
write!(ret, "USB debug port locked out; one word at 0x80000000 is disclosable via USB.").unwrap();
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ impl Spinor {
|
|||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
fn send_write_region(&mut self, wr: &WriteRegion) -> Result<(), SpinorError> {
|
||||
fn send_write_region(&self, wr: &WriteRegion) -> Result<(), SpinorError> {
|
||||
let mut buf = Buffer::into_buf(*wr).or(Err(SpinorError::IpcError))?;
|
||||
buf.lend_mut(self.conn, Opcode::WriteRegion.to_u32().unwrap()).or(Err(SpinorError::IpcError))?;
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ impl Spinor {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn send_write_region(&mut self, wr: &WriteRegion) -> Result<(), SpinorError> {
|
||||
fn send_write_region(&self, wr: &WriteRegion) -> Result<(), SpinorError> {
|
||||
let mut i = 0;
|
||||
if !wr.clean_patch {
|
||||
assert!((wr.start & 0xFFF) == 0, "erasing is required, but start address is not erase-sector aligned");
|
||||
|
|
@ -109,7 +109,7 @@ impl Spinor {
|
|||
/// Aside from that, it's the wild west! Think of this as `dd` into a raw disk device node, and not a filesystem-abstracted `write`
|
||||
/// `region` is a slice that points to the target region that we wish to patch -- ostensibly we should have access to it, so this should
|
||||
/// just be the MemoryRange turned into a slice.
|
||||
/// `region_base` is the base address of `region`, given as an offset from base of FLASH (that is, physical address minus 0x2000_0000)
|
||||
/// `region_base` is the physical base address of `region`, given as an offset from base of FLASH (that is, physical address minus 0x2000_0000)
|
||||
/// this *must* be aligned to an erase sector.
|
||||
/// `patch_data` is a slice that contains exactly the data we want to have patched into FLASH. If you're lazy and you just send a large
|
||||
/// amount of unchanged data with a couple small changes scattered about, this will not be "smart" about it and do a diff and
|
||||
|
|
@ -122,7 +122,7 @@ impl Spinor {
|
|||
/// Notes:
|
||||
/// - the server will entirely skip writing over 256-byte pages that are blank. So, if the goal is to erase a region,
|
||||
/// call patch with data of all 0xFF - this will effectively only do an erase, but no subsequent writes.
|
||||
pub fn patch(&mut self, region: &[u8], region_base: u32, patch_data: &[u8], patch_index: u32) -> Result<(), SpinorError> {
|
||||
pub fn patch(&self, region: &[u8], region_base: u32, patch_data: &[u8], patch_index: u32) -> Result<(), SpinorError> {
|
||||
let align_mask = self.erase_alignment() - 1;
|
||||
if (region_base & align_mask) != 0 {
|
||||
return Err(SpinorError::AlignmentError);
|
||||
|
|
|
|||
Loading…
Reference in a new issue