diff --git a/precursors/rom.db b/precursors/rom.db old mode 100644 new mode 100755 index 50a236ca2..21af47436 --- a/precursors/rom.db +++ b/precursors/rom.db @@ -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' diff --git a/precursors/soc.svd b/precursors/soc.svd index 19ab54927..6f01064bc 100755 --- a/precursors/soc.svd +++ b/precursors/soc.svd @@ -3,7 +3,7 @@ litex SOC - + 8 32 @@ -1238,10 +1238,10 @@ register to disable individual events.]]> GIT_GITREV 0x0014 - 0xe64c9cef + 0x890b90e7 32 @@ -1258,7 +1258,7 @@ the exact git version used to build this firmware.]]> is ``1``, then the repository this was built from has one additional commit beyond the tag indicated in `MAJOR`, `MINOR`, and `REVISION`.]]> 0x0018 - 0x43 + 0x46 32 @@ -3584,7 +3584,7 @@ inject too fast.]]> SEED1 0x0000 - 0x19f188fb + 0x4f340196 32 @@ -3599,7 +3599,7 @@ inject too fast.]]> SEED0 0x0004 - 0x53401497 + 0x77c237e8 32 diff --git a/precursors/soc_csr.bin b/precursors/soc_csr.bin index 50a8cb509..45cd228ea 100755 Binary files a/precursors/soc_csr.bin and b/precursors/soc_csr.bin differ diff --git a/services/gam/src/main.rs b/services/gam/src/main.rs index 5ab211732..a30b4204a 100644 --- a/services/gam/src/main.rs +++ b/services/gam/src/main.rs @@ -89,7 +89,6 @@ pub(crate) struct UxContext { pub audioframe_id: Option, } 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; diff --git a/services/root-keys/locales/i18n.json b/services/root-keys/locales/i18n.json index a66a9a72a..0426e7c0d 100644 --- a/services/root-keys/locales/i18n.json +++ b/services/root-keys/locales/i18n.json @@ -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?", diff --git a/services/root-keys/src/api.rs b/services/root-keys/src/api.rs index b365ce8a8..d19f1802d 100644 --- a/services/root-keys/src/api.rs +++ b/services/root-keys/src/api.rs @@ -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, -} \ No newline at end of file +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum RootkeyResult { + AlignmentError, + KeyError, + IntegrityError, + FlashError, +} diff --git a/services/root-keys/src/implementation.rs b/services/root-keys/src/implementation.rs index 440904e03..f179cf135 100644 --- a/services/root-keys/src/implementation.rs +++ b/services/root-keys/src/implementation.rs @@ -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, 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, - 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, // 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::() + } + pub fn gateware_base(&self) -> u32 { self.gateware_base } + pub fn staging(&self) -> &[u8] { + self.staging_mr.as_slice::() + } + pub fn staging_base(&self) -> u32 { self.staging_base } + pub fn loader_code(&self) -> &[u8] { + self.loader_code_mr.as_slice::() + } + pub fn loader_base(&self) -> u32 { self.loader_code_base } + pub fn kernel(&self) -> &[u8] { + self.kernel_mr.as_slice::() + } + 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::(); + // 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::()*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::()*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::(); - // 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::()*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::()*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::(); - 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::(); - 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::(); + 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::()*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::(); + // 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::(); + 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::(); - let gateware_src = self.gateware.as_slice::(); + 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::(); + 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::(); + 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. diff --git a/services/root-keys/src/key2bits/key2bits.py b/services/root-keys/src/key2bits/key2bits.py index f3c8137ed..c67d7a0d5 100755 --- a/services/root-keys/src/key2bits/key2bits.py +++ b/services/root-keys/src/key2bits/key2bits.py @@ -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, Option) {{\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, 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(""" } } diff --git a/services/root-keys/src/key2bits/patch.rs b/services/root-keys/src/key2bits/patch.rs old mode 100644 new mode 100755 index 0f3c93a98..db9094ac8 --- a/services/root-keys/src/key2bits/patch.rs +++ b/services/root-keys/src/key2bits/patch.rs @@ -1,5 +1,5 @@ -//! this file was auto-generated by key2bits.py on 2021-08-05 04:52:22.858205 +//! this file was auto-generated by key2bits.py on 2021-08-06 22:59:51.977948 //! manual regeneration is needed for the following cases: //! - rom.db changes (that is, the KEYROM pcells have been moved to a new location) //! - entirely different FPGA target (in which case, the db/ files also need to be regenerated @@ -54,7 +54,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, Option) { +pub fn patch_frame(frame: u32, offset: u32, rom: &[u32]) -> Option<(u32, u32)> { let frame_35e: PatchFrame = PatchFrame { frame: 0x35e, words: [ @@ -9322,13 +9322,13 @@ pub fn patch_frame(frame: u32, offset: u32, rom: &[u32; 256]) -> (Option, O data_inv |= 1 << bit; } } - return (Some(data), Some(data_inv)) + return Some((data, data_inv)) } } } } - return (None, None) + return None } /// a fast check to see if a given frame is within the range of frames that are @@ -9346,522 +9346,522 @@ mod tests { #[test] fn check_frames() { const ROM: [u32; 256] = [ - 0x60dcb193, - 0x45ec46e3, - 0x8a603456, - 0x18be6e6a, - 0x758b9825, - 0x744c054a, - 0xde45b1ee, - 0xa31c7a2d, - 0xa17eb4ec, - 0xd3b82a54, - 0xc1bd97d8, - 0xe44ec5a7, - 0x256a20a2, - 0xc9915790, - 0x1b7c3c8c, - 0x19cae7df, - 0x22742779, - 0xb6370eb5, - 0x2b9505bb, - 0x19882bf0, - 0x43f0739a, - 0xc8e96614, - 0x444fd1a3, - 0x6dfe38ab, - 0xa35a461f, - 0xe15e9c9d, - 0x51ee1e39, - 0xa6226fcb, - 0x0ac1a97c, - 0xad3f88db, - 0x731d69c4, - 0xcec18e49, - 0xa2323a99, - 0xc395d5a9, - 0x57fc4e69, - 0x75fb524f, - 0xc2e3510a, - 0x059a65cd, - 0xfc559fd2, - 0x2f5876e1, - 0xd9c64259, - 0xb7245db6, - 0x7966d52e, - 0x084f424d, - 0x50b6e873, - 0x506b4533, - 0x1a003ad1, - 0x8014c795, - 0x041eb824, - 0x871fbccf, - 0xbdaf532a, - 0x4c59ec86, - 0x9d489e66, - 0x549b3d1d, - 0xcbc67524, - 0xa2ccc7f4, - 0x81ef25a4, - 0x4cc754b9, - 0xae5ff5d3, - 0x3864eedc, - 0x5d9c9961, - 0x628ffd74, - 0xe155d9ad, - 0x5f10cf99, - 0x5ce6cef2, - 0x8880d25b, - 0xc3e394ea, - 0xdc1408dc, - 0x89ddb484, - 0x87671ca1, - 0xc3f89512, - 0x3123d2ba, - 0xfd5b4646, - 0x432af9d4, - 0xe8e6d76f, - 0x126ab69e, - 0x4781f5a4, - 0xd05d5491, - 0x24d768a6, - 0xe0ad5938, - 0xf6891af7, - 0x307c7e49, - 0x3c20e9b8, - 0xdffdbba7, - 0x6ab2f819, - 0x4122f8ee, - 0x2ce7b263, - 0xd62ad4fe, - 0x92a9056f, - 0xa4299bab, - 0xf576e971, - 0x50a995a2, - 0x8fdafea8, - 0x9f486305, - 0xf84d6d8d, - 0xa557f32c, - 0x942e4e6b, - 0x8a04e58c, - 0xeb007188, - 0x73802f73, - 0x1766027d, - 0xf896edd5, - 0x287e06d7, - 0x42270ef8, - 0x5e431aa2, - 0xb41835eb, - 0x82cba690, - 0x55a52940, - 0xf21903e7, - 0x8555f4f7, - 0x83e2d1ad, - 0x5ec4af4a, - 0x05382947, - 0xa7ebfc3f, - 0x0b9a918a, - 0xa5cbcecd, - 0x71614505, - 0xa5a972f9, - 0x4e6340a0, - 0x8b51d8fa, - 0xe57da393, - 0x11422dae, - 0x1e77996d, - 0x06fa9308, - 0xe94af229, - 0x1eff351c, - 0x12aee9c9, - 0x0e0d7f0c, - 0x97518f90, - 0xd7ce029c, - 0x2356463d, - 0xb8f110ff, - 0x7d646be7, - 0x85bffaed, - 0x8d50d2eb, - 0x0cc81e20, - 0x358e8940, - 0x85386e8e, - 0xd88c7723, - 0xf4b24b3d, - 0xb5c02fbe, - 0xe0985489, - 0x2a912488, - 0x22a32f98, - 0xc4665957, - 0xe642354b, - 0x4205be10, - 0xeed77f26, - 0x08bfcf79, - 0x3dd0a539, - 0xf6a645d6, - 0x8d0121af, - 0xd8e862ab, - 0xf4602c60, - 0x0ce78535, - 0x2a4d8543, - 0x4f8e3912, - 0x5cdfb50d, - 0x415dbafc, - 0x332bbe9a, - 0xce3ad2d0, - 0xb0bee3b8, - 0xf612332a, - 0x5dfa55b1, - 0xec706a23, - 0xbf85ecc3, - 0xaf2abac8, - 0xfdbb14fa, - 0xcc032e53, - 0xae703c79, - 0x2a23461c, - 0x147d4d55, - 0xc54c8736, - 0xb71d1a5b, - 0x3eb770d7, - 0x29508711, - 0xdb2e9e6a, - 0x760079c4, - 0x8c597021, - 0x0ff36411, - 0xa331bf6f, - 0x456fb279, - 0x1066f0e4, - 0x91690f2c, - 0x64eab33a, - 0x0c1f7865, - 0x5fecb278, - 0x6b037dad, - 0xe1b83785, - 0x1ab19abc, - 0x4f4cf7e2, - 0x02a8f3b8, - 0x4eb8d4fc, - 0x2485966e, - 0x3b2d416c, - 0x85fc9c8e, - 0x88a7abdd, - 0x2258028d, - 0x6a3966db, - 0xaa124f67, - 0x58458991, - 0x99f42695, - 0x65a062eb, - 0xcf4c5337, - 0x8c279702, - 0x0b916053, - 0x0f233f8c, - 0x8b7a01ea, - 0xa8c8ca23, - 0xd707da1b, - 0x98134842, - 0x72130ce5, - 0xfe10ca30, - 0x302cf4b9, - 0xf0192fd9, - 0x4f30bc2f, - 0xf5aff866, - 0x1518d44f, - 0x19a95afe, - 0x5afc5c44, - 0xab9e2766, - 0xe017f98d, - 0x85564136, - 0x2f143c8c, - 0xe3f58f94, - 0xb84480b6, - 0xf76ba411, - 0x064aae97, - 0x870c2c16, - 0xdc547221, - 0x34242221, - 0x619107f1, - 0x97a73bb3, - 0x691bfbda, - 0x0294adc1, - 0xb9f111b5, - 0x69a7e467, - 0x0695d95b, - 0x96c6d960, - 0x8ee932c4, - 0xc637b877, - 0xa8a6ea9b, - 0xa268d9c9, - 0x203b3e16, - 0xecfdb4b4, - 0x8fc44005, - 0xcbd8fc91, - 0x90446dcf, - 0x55404748, - 0xd80b686c, - 0x811250ba, - 0xbe118105, - 0x4dc55915, - 0x69b3fb34, - 0x918d9997, - 0x161d0c30, + 0xe2c29a8d, + 0x6ed4ab79, + 0xb16f221e, + 0xbdb35567, + 0xe6e3ec5e, + 0x30f54f1b, + 0x85bbaa20, + 0x73509306, + 0x5d4fbedb, + 0x08520d0b, + 0x61608b76, + 0x046f795f, + 0x50406041, + 0x97cd29cd, + 0xa558f4b7, + 0xfdc154d7, + 0xf3ccdf0e, + 0x5059dfe5, + 0xb9f98848, + 0x37753a30, + 0xa67269bd, + 0xbce46d93, + 0x1e950af5, + 0x4d0c7874, + 0x4ead2c10, + 0x31a1c25c, + 0x8b8efd23, + 0xe2bffd4e, + 0x1fcfe7c2, + 0x5ab5a4ea, + 0x6c9cfa3a, + 0xcf87266f, + 0xe2a9f15f, + 0x6b4c8e83, + 0xb8e6a393, + 0x2e14bd40, + 0x92290e09, + 0x817fd5a7, + 0x3db19540, + 0x9ce1bf98, + 0x3598f580, + 0xe775ee2a, + 0x447019ef, + 0x799d2722, + 0x648f9054, + 0x1d47c02b, + 0x50a744fa, + 0xb0fda4e5, + 0x234d2557, + 0x6e7c4d99, + 0xfae5353f, + 0x7cd7c10e, + 0xa09c51c3, + 0xb2b52fe0, + 0xb858436c, + 0xc77132bd, + 0xd295e698, + 0x5d26fab8, + 0x97606a07, + 0xf4d466d8, + 0x2472d2eb, + 0x02a40805, + 0x61148e49, + 0x473b426d, + 0x7bef5ac7, + 0xbef4da92, + 0xfa1caa63, + 0x68c921dc, + 0x9d932b5c, + 0xc60c3878, + 0x04b4251d, + 0xa4059626, + 0xd7d32c63, + 0xdb5e2955, + 0x742880d1, + 0xa699279f, + 0x837259d9, + 0xb85932cd, + 0x1f7d0e30, + 0x341a6990, + 0xfbdb2a64, + 0x27f13cde, + 0x1a7f88d9, + 0xccc4d165, + 0xe113709f, + 0xaefce3df, + 0x48652042, + 0x14c9fbb7, + 0xbbd18eef, + 0xe2e9e12b, + 0x34664bba, + 0xa033a8f3, + 0x6a3d8682, + 0x193ec130, + 0x711be3fc, + 0x7b744065, + 0x1f89649d, + 0xe9aad601, + 0x72008961, + 0xc7eed6bb, + 0x340dacf0, + 0xaf233ccc, + 0xa09c474a, + 0x97ab7f05, + 0xcae30866, + 0x71643822, + 0x3387175c, + 0xc6019281, + 0x8f6b7bbd, + 0xe41021ea, + 0x1303e5b9, + 0x584eb03a, + 0x342eda72, + 0x9cd2c543, + 0x72d06217, + 0xe9c0fd8c, + 0xde729554, + 0xabdfb7f3, + 0x488098e7, + 0xa0db86f2, + 0xfde0bc0f, + 0x9d700cb7, + 0xe6b6f6d0, + 0x14822d5b, + 0x5cd88890, + 0xa61a3183, + 0x90acf502, + 0x85ffef4b, + 0x7de9050d, + 0xf72cf91e, + 0xae20afc4, + 0xfc7027ef, + 0xa61bca63, + 0xa81e27dd, + 0x7397460f, + 0xf0a8c5f2, + 0x4b5eb90d, + 0xb313d408, + 0xa252e509, + 0xfaf99aa8, + 0xd060f956, + 0xda421f71, + 0xbb2617d2, + 0xf5adf058, + 0xc4b0d515, + 0x660c6d58, + 0x252e54b7, + 0x0163f07a, + 0x2cb89bf1, + 0x28323098, + 0x2306064f, + 0xb3aee2d3, + 0xcc38bbe6, + 0xc96a809f, + 0x21701756, + 0x521d2b7d, + 0xfe5894e8, + 0xbc5ad11b, + 0x8916b836, + 0xff28656f, + 0x9bb792d2, + 0xbb1bf9ce, + 0x4704011a, + 0x5d43f48f, + 0xb9f53e6a, + 0x70991a45, + 0x8889584b, + 0x685f276b, + 0x9e5eacef, + 0xa0507797, + 0x7e503d4a, + 0xcbf7967f, + 0x8fa77607, + 0x6af416b1, + 0x91f72a7b, + 0xbe99b070, + 0xb7669cd8, + 0xec027852, + 0x16fc5ee6, + 0xc56c663d, + 0xa40850ea, + 0x7f3df3b2, + 0x405e6ef0, + 0x7f7fcbc5, + 0xa4362ee8, + 0x2fbd00ff, + 0x6d335ec6, + 0xacb8cc81, + 0x600c65b2, + 0x53f28432, + 0x02310784, + 0x781e2821, + 0x67cc2e78, + 0x694612a9, + 0x76227435, + 0xf59e8dd9, + 0x3fd54e80, + 0xa608109f, + 0xf6344764, + 0xbd103659, + 0x3000bcb4, + 0x914b49cd, + 0x94682578, + 0xa3414299, + 0x84c37993, + 0xa737e429, + 0xc985b4df, + 0x2d2eb0c3, + 0xedf3006e, + 0x451f2df9, + 0x05c8dea2, + 0xa88a06bf, + 0x6bdc8700, + 0xa6be32c6, + 0x88a1e406, + 0x41cc591d, + 0x259a989c, + 0xc30625e8, + 0xb6efeaaa, + 0x0dc2a22d, + 0x9898a70d, + 0xdb6262ab, + 0x73398b8f, + 0x2614c496, + 0xd844a80a, + 0x855e7043, + 0xa030a188, + 0x71a81074, + 0x260d38a0, + 0x94d76d7e, + 0xb5df9c5f, + 0x2d4d2bb1, + 0x33a1c5d4, + 0x91ef896d, + 0xa79cf24a, + 0x63f3962b, + 0x9571f480, + 0x337fd57a, + 0x94a3934e, + 0xa4ec9a07, + 0x37d38759, + 0x2f5175d5, + 0x07b197bc, + 0x35559b37, + 0xbb3565be, + 0x8572992a, + 0xc50d3eb1, + 0x438cfb26, + 0x81cc0940, + 0xaa840bd4, + 0x0cee83cb, + 0xcb9928a1, + 0x9d478634, + 0xdf0e6392, + 0xa74a58c7, + 0xf3f6cb46, ]; - assert_eq!(crate::patch_frame(862, 0, ROM), (Some(0x1c28396a), Some(!0x1c28396a))); - assert_eq!(crate::patch_frame(862, 1, ROM), (Some(0xd99cd736), Some(!0xd99cd736))); - assert_eq!(crate::patch_frame(862, 2, ROM), (Some(0xf104525a), Some(!0xf104525a))); - assert_eq!(crate::patch_frame(862, 3, ROM), (Some(0x46e41ee4), Some(!0x46e41ee4))); - assert_eq!(crate::patch_frame(862, 4, ROM), (Some(0xca1a726f), Some(!0xca1a726f))); - assert_eq!(crate::patch_frame(862, 5, ROM), (Some(0xcda13d4f), Some(!0xcda13d4f))); - assert_eq!(crate::patch_frame(862, 6, ROM), (Some(0xb187b191), Some(!0xb187b191))); - assert_eq!(crate::patch_frame(862, 7, ROM), (Some(0xec559790), Some(!0xec559790))); - assert_eq!(crate::patch_frame(862, 8, ROM), (Some(0x3b90f6fa), Some(!0x3b90f6fa))); - assert_eq!(crate::patch_frame(862, 9, ROM), (Some(0x89b00ad6), Some(!0x89b00ad6))); - assert_eq!(crate::patch_frame(862, 10, ROM), (Some(0x2fadae3a), Some(!0x2fadae3a))); - assert_eq!(crate::patch_frame(862, 11, ROM), (Some(0x8e8820da), Some(!0x8e8820da))); - assert_eq!(crate::patch_frame(862, 12, ROM), (Some(0x317b2477), Some(!0x317b2477))); - assert_eq!(crate::patch_frame(862, 13, ROM), (Some(0x2748da89), Some(!0x2748da89))); - assert_eq!(crate::patch_frame(862, 14, ROM), (Some(0xaacf969b), Some(!0xaacf969b))); - assert_eq!(crate::patch_frame(862, 15, ROM), (Some(0xf704b11a), Some(!0xf704b11a))); - assert_eq!(crate::patch_frame(862, 16, ROM), (Some(0x24484bd9), Some(!0x24484bd9))); - assert_eq!(crate::patch_frame(862, 17, ROM), (Some(0xc3b521ad), Some(!0xc3b521ad))); - assert_eq!(crate::patch_frame(862, 18, ROM), (Some(0xd967029c), Some(!0xd967029c))); - assert_eq!(crate::patch_frame(862, 19, ROM), (Some(0x389ca14e), Some(!0x389ca14e))); - assert_eq!(crate::patch_frame(862, 20, ROM), (Some(0xf0de2bbb), Some(!0xf0de2bbb))); - assert_eq!(crate::patch_frame(862, 21, ROM), (Some(0xd7bb4ae4), Some(!0xd7bb4ae4))); - assert_eq!(crate::patch_frame(862, 22, ROM), (Some(0xa8830300), Some(!0xa8830300))); - assert_eq!(crate::patch_frame(862, 23, ROM), (Some(0xfb04a665), Some(!0xfb04a665))); - assert_eq!(crate::patch_frame(862, 24, ROM), (Some(0xd2edc5da), Some(!0xd2edc5da))); - assert_eq!(crate::patch_frame(862, 25, ROM), (Some(0x5a655ee1), Some(!0x5a655ee1))); - assert_eq!(crate::patch_frame(862, 26, ROM), (Some(0xfe0332bc), Some(!0xfe0332bc))); - assert_eq!(crate::patch_frame(862, 27, ROM), (Some(0xa7555417), Some(!0xa7555417))); - assert_eq!(crate::patch_frame(862, 28, ROM), (Some(0x5bd66172), Some(!0x5bd66172))); - assert_eq!(crate::patch_frame(862, 29, ROM), (Some(0x0f52ac94), Some(!0x0f52ac94))); - assert_eq!(crate::patch_frame(862, 30, ROM), (Some(0x2fef99fe), Some(!0x2fef99fe))); - assert_eq!(crate::patch_frame(862, 31, ROM), (Some(0x78c050b7), Some(!0x78c050b7))); - assert_eq!(crate::patch_frame(863, 0, ROM), (Some(0xd9cd4d30), Some(!0xd9cd4d30))); - assert_eq!(crate::patch_frame(863, 1, ROM), (Some(0x9749e14c), Some(!0x9749e14c))); - assert_eq!(crate::patch_frame(863, 2, ROM), (Some(0xeb09eb93), Some(!0xeb09eb93))); - assert_eq!(crate::patch_frame(863, 3, ROM), (Some(0xdb9f71ea), Some(!0xdb9f71ea))); - assert_eq!(crate::patch_frame(863, 4, ROM), (Some(0x97b077d3), Some(!0x97b077d3))); - assert_eq!(crate::patch_frame(863, 5, ROM), (Some(0x375bdd91), Some(!0x375bdd91))); - assert_eq!(crate::patch_frame(863, 6, ROM), (Some(0x66d9e1f8), Some(!0x66d9e1f8))); - assert_eq!(crate::patch_frame(863, 7, ROM), (Some(0x77b78dbd), Some(!0x77b78dbd))); - assert_eq!(crate::patch_frame(863, 8, ROM), (Some(0xb87cb483), Some(!0xb87cb483))); - assert_eq!(crate::patch_frame(863, 9, ROM), (Some(0x9c56de51), Some(!0x9c56de51))); - assert_eq!(crate::patch_frame(863, 10, ROM), (Some(0x5d4d3429), Some(!0x5d4d3429))); - assert_eq!(crate::patch_frame(863, 11, ROM), (Some(0x6e7d5d0e), Some(!0x6e7d5d0e))); - assert_eq!(crate::patch_frame(863, 12, ROM), (Some(0x036d2fae), Some(!0x036d2fae))); - assert_eq!(crate::patch_frame(863, 13, ROM), (Some(0x0eea573e), Some(!0x0eea573e))); - assert_eq!(crate::patch_frame(863, 14, ROM), (Some(0xcbc822a2), Some(!0xcbc822a2))); - assert_eq!(crate::patch_frame(863, 15, ROM), (Some(0x97ad008d), Some(!0x97ad008d))); - assert_eq!(crate::patch_frame(863, 16, ROM), (Some(0x1c4cacd6), Some(!0x1c4cacd6))); - assert_eq!(crate::patch_frame(863, 17, ROM), (Some(0x333c496a), Some(!0x333c496a))); - assert_eq!(crate::patch_frame(863, 18, ROM), (Some(0x6244b0d3), Some(!0x6244b0d3))); - assert_eq!(crate::patch_frame(863, 19, ROM), (Some(0x0d0ef77f), Some(!0x0d0ef77f))); - assert_eq!(crate::patch_frame(863, 20, ROM), (Some(0x430c60d7), Some(!0x430c60d7))); - assert_eq!(crate::patch_frame(863, 21, ROM), (Some(0x3f1acb40), Some(!0x3f1acb40))); - assert_eq!(crate::patch_frame(863, 22, ROM), (Some(0xc01af6f4), Some(!0xc01af6f4))); - assert_eq!(crate::patch_frame(863, 23, ROM), (Some(0x846ec7e3), Some(!0x846ec7e3))); - assert_eq!(crate::patch_frame(863, 24, ROM), (Some(0x3d428c2c), Some(!0x3d428c2c))); - assert_eq!(crate::patch_frame(863, 25, ROM), (Some(0x25d91899), Some(!0x25d91899))); - assert_eq!(crate::patch_frame(863, 26, ROM), (Some(0x11aa5774), Some(!0x11aa5774))); - assert_eq!(crate::patch_frame(863, 27, ROM), (Some(0xc4a14714), Some(!0xc4a14714))); - assert_eq!(crate::patch_frame(863, 28, ROM), (Some(0xb69c4eb8), Some(!0xb69c4eb8))); - assert_eq!(crate::patch_frame(863, 29, ROM), (Some(0x186e3951), Some(!0x186e3951))); - assert_eq!(crate::patch_frame(863, 30, ROM), (Some(0x58abedb1), Some(!0x58abedb1))); - assert_eq!(crate::patch_frame(863, 31, ROM), (Some(0xe5af1a89), Some(!0xe5af1a89))); - assert_eq!(crate::patch_frame(864, 0, ROM), (Some(0x78a08520), Some(!0x78a08520))); - assert_eq!(crate::patch_frame(864, 1, ROM), (Some(0x4cb856a0), Some(!0x4cb856a0))); - assert_eq!(crate::patch_frame(864, 2, ROM), (Some(0x1ba8f3a7), Some(!0x1ba8f3a7))); - assert_eq!(crate::patch_frame(864, 3, ROM), (Some(0x599f1f4d), Some(!0x599f1f4d))); - assert_eq!(crate::patch_frame(864, 4, ROM), (Some(0x504b488f), Some(!0x504b488f))); - assert_eq!(crate::patch_frame(864, 5, ROM), (Some(0x1da840aa), Some(!0x1da840aa))); - assert_eq!(crate::patch_frame(864, 6, ROM), (Some(0x93d0b107), Some(!0x93d0b107))); - assert_eq!(crate::patch_frame(864, 7, ROM), (Some(0xeca87e9d), Some(!0xeca87e9d))); - assert_eq!(crate::patch_frame(864, 8, ROM), (Some(0xc092d133), Some(!0xc092d133))); - assert_eq!(crate::patch_frame(864, 9, ROM), (Some(0x4b15b555), Some(!0x4b15b555))); - assert_eq!(crate::patch_frame(864, 10, ROM), (Some(0x07abd9ee), Some(!0x07abd9ee))); - assert_eq!(crate::patch_frame(864, 11, ROM), (Some(0x98598f87), Some(!0x98598f87))); - assert_eq!(crate::patch_frame(864, 12, ROM), (Some(0xa39a9b8d), Some(!0xa39a9b8d))); - assert_eq!(crate::patch_frame(864, 13, ROM), (Some(0xc3fb9406), Some(!0xc3fb9406))); - assert_eq!(crate::patch_frame(864, 14, ROM), (Some(0x0aa60713), Some(!0x0aa60713))); - assert_eq!(crate::patch_frame(864, 15, ROM), (Some(0xcd345b17), Some(!0xcd345b17))); - assert_eq!(crate::patch_frame(864, 16, ROM), (Some(0x128a530c), Some(!0x128a530c))); - assert_eq!(crate::patch_frame(864, 17, ROM), (Some(0xc10e5e6a), Some(!0xc10e5e6a))); - assert_eq!(crate::patch_frame(864, 18, ROM), (Some(0x5c99a769), Some(!0x5c99a769))); - assert_eq!(crate::patch_frame(864, 19, ROM), (Some(0xfe87da62), Some(!0xfe87da62))); - assert_eq!(crate::patch_frame(864, 20, ROM), (Some(0x9452d9c3), Some(!0x9452d9c3))); - assert_eq!(crate::patch_frame(864, 21, ROM), (Some(0xdc4686a4), Some(!0xdc4686a4))); - assert_eq!(crate::patch_frame(864, 22, ROM), (Some(0xa4727203), Some(!0xa4727203))); - assert_eq!(crate::patch_frame(864, 23, ROM), (Some(0x1456b10a), Some(!0x1456b10a))); - assert_eq!(crate::patch_frame(864, 24, ROM), (Some(0x753515a7), Some(!0x753515a7))); - assert_eq!(crate::patch_frame(864, 25, ROM), (Some(0xc2178583), Some(!0xc2178583))); - assert_eq!(crate::patch_frame(864, 26, ROM), (Some(0xf5de069e), Some(!0xf5de069e))); - assert_eq!(crate::patch_frame(864, 27, ROM), (Some(0x0213334d), Some(!0x0213334d))); - assert_eq!(crate::patch_frame(864, 28, ROM), (Some(0x03c67db4), Some(!0x03c67db4))); - assert_eq!(crate::patch_frame(864, 29, ROM), (Some(0x19804e86), Some(!0x19804e86))); - assert_eq!(crate::patch_frame(864, 30, ROM), (Some(0xd25ce8a0), Some(!0xd25ce8a0))); - assert_eq!(crate::patch_frame(864, 31, ROM), (Some(0x3ba0ef90), Some(!0x3ba0ef90))); - assert_eq!(crate::patch_frame(865, 0, ROM), (Some(0x6fa56ab9), Some(!0x6fa56ab9))); - assert_eq!(crate::patch_frame(865, 1, ROM), (Some(0xd8a82864), Some(!0xd8a82864))); - assert_eq!(crate::patch_frame(865, 2, ROM), (Some(0x540c394c), Some(!0x540c394c))); - assert_eq!(crate::patch_frame(865, 3, ROM), (Some(0x4b17dec1), Some(!0x4b17dec1))); - assert_eq!(crate::patch_frame(865, 4, ROM), (Some(0x4fb46d2d), Some(!0x4fb46d2d))); - assert_eq!(crate::patch_frame(865, 5, ROM), (Some(0x7eb6a66b), Some(!0x7eb6a66b))); - assert_eq!(crate::patch_frame(865, 6, ROM), (Some(0xd4c53913), Some(!0xd4c53913))); - assert_eq!(crate::patch_frame(865, 7, ROM), (Some(0x33f9f11d), Some(!0x33f9f11d))); - assert_eq!(crate::patch_frame(865, 8, ROM), (Some(0x768869ef), Some(!0x768869ef))); - assert_eq!(crate::patch_frame(865, 9, ROM), (Some(0xc2ea4c90), Some(!0xc2ea4c90))); - assert_eq!(crate::patch_frame(865, 10, ROM), (Some(0x9cd3a380), Some(!0x9cd3a380))); - assert_eq!(crate::patch_frame(865, 11, ROM), (Some(0x17851733), Some(!0x17851733))); - assert_eq!(crate::patch_frame(865, 12, ROM), (Some(0x5ae07b9f), Some(!0x5ae07b9f))); - assert_eq!(crate::patch_frame(865, 13, ROM), (Some(0x374bb33c), Some(!0x374bb33c))); - assert_eq!(crate::patch_frame(865, 14, ROM), (Some(0xa871852d), Some(!0xa871852d))); - assert_eq!(crate::patch_frame(865, 15, ROM), (Some(0x665fc267), Some(!0x665fc267))); - assert_eq!(crate::patch_frame(865, 16, ROM), (Some(0x3bb486d8), Some(!0x3bb486d8))); - assert_eq!(crate::patch_frame(865, 17, ROM), (Some(0xd6d7acec), Some(!0xd6d7acec))); - assert_eq!(crate::patch_frame(865, 18, ROM), (Some(0x0e01cb2f), Some(!0x0e01cb2f))); - assert_eq!(crate::patch_frame(865, 19, ROM), (Some(0x8b6bfd0e), Some(!0x8b6bfd0e))); - assert_eq!(crate::patch_frame(865, 20, ROM), (Some(0x7ca00c5e), Some(!0x7ca00c5e))); - assert_eq!(crate::patch_frame(865, 21, ROM), (Some(0x4c1df468), Some(!0x4c1df468))); - assert_eq!(crate::patch_frame(865, 22, ROM), (Some(0x4ef3fe1e), Some(!0x4ef3fe1e))); - assert_eq!(crate::patch_frame(865, 23, ROM), (Some(0x7a5146aa), Some(!0x7a5146aa))); - assert_eq!(crate::patch_frame(865, 24, ROM), (Some(0x12d01255), Some(!0x12d01255))); - assert_eq!(crate::patch_frame(865, 25, ROM), (Some(0x2af51b14), Some(!0x2af51b14))); - assert_eq!(crate::patch_frame(865, 26, ROM), (Some(0xb6225ed5), Some(!0xb6225ed5))); - assert_eq!(crate::patch_frame(865, 27, ROM), (Some(0xc38612d6), Some(!0xc38612d6))); - assert_eq!(crate::patch_frame(865, 28, ROM), (Some(0x4a20b05a), Some(!0x4a20b05a))); - assert_eq!(crate::patch_frame(865, 29, ROM), (Some(0xd52aa945), Some(!0xd52aa945))); - assert_eq!(crate::patch_frame(865, 30, ROM), (Some(0x2b9568a2), Some(!0x2b9568a2))); - assert_eq!(crate::patch_frame(865, 31, ROM), (Some(0xcf7ac88d), Some(!0xcf7ac88d))); - assert_eq!(crate::patch_frame(868, 0, ROM), (Some(0x395d7a26), Some(!0x395d7a26))); - assert_eq!(crate::patch_frame(868, 1, ROM), (Some(0x0bbaadc0), Some(!0x0bbaadc0))); - assert_eq!(crate::patch_frame(868, 2, ROM), (Some(0xe0aa6903), Some(!0xe0aa6903))); - assert_eq!(crate::patch_frame(868, 3, ROM), (Some(0x283a700b), Some(!0x283a700b))); - assert_eq!(crate::patch_frame(868, 4, ROM), (Some(0xb3ebcf80), Some(!0xb3ebcf80))); - assert_eq!(crate::patch_frame(868, 5, ROM), (Some(0x9e30ce90), Some(!0x9e30ce90))); - assert_eq!(crate::patch_frame(868, 6, ROM), (Some(0xf50c3b9b), Some(!0xf50c3b9b))); - assert_eq!(crate::patch_frame(868, 7, ROM), (Some(0xc9b85852), Some(!0xc9b85852))); - assert_eq!(crate::patch_frame(868, 8, ROM), (Some(0x6184ab42), Some(!0x6184ab42))); - assert_eq!(crate::patch_frame(868, 9, ROM), (Some(0x144e9f35), Some(!0x144e9f35))); - assert_eq!(crate::patch_frame(868, 10, ROM), (Some(0x91e3c70a), Some(!0x91e3c70a))); - assert_eq!(crate::patch_frame(868, 11, ROM), (Some(0xf0924c53), Some(!0xf0924c53))); - assert_eq!(crate::patch_frame(868, 12, ROM), (Some(0x800f1cdf), Some(!0x800f1cdf))); - assert_eq!(crate::patch_frame(868, 13, ROM), (Some(0x7b44f3bf), Some(!0x7b44f3bf))); - assert_eq!(crate::patch_frame(868, 14, ROM), (Some(0xde057ba5), Some(!0xde057ba5))); - assert_eq!(crate::patch_frame(868, 15, ROM), (Some(0x86c30365), Some(!0x86c30365))); - assert_eq!(crate::patch_frame(868, 16, ROM), (Some(0x75ca8606), Some(!0x75ca8606))); - assert_eq!(crate::patch_frame(868, 17, ROM), (Some(0x69033534), Some(!0x69033534))); - assert_eq!(crate::patch_frame(868, 18, ROM), (Some(0x60ba6f09), Some(!0x60ba6f09))); - assert_eq!(crate::patch_frame(868, 19, ROM), (Some(0xa1b09d5d), Some(!0xa1b09d5d))); - assert_eq!(crate::patch_frame(868, 20, ROM), (Some(0x978bd2e6), Some(!0x978bd2e6))); - assert_eq!(crate::patch_frame(868, 21, ROM), (Some(0x321c8ed8), Some(!0x321c8ed8))); - assert_eq!(crate::patch_frame(868, 22, ROM), (Some(0x08c7f825), Some(!0x08c7f825))); - assert_eq!(crate::patch_frame(868, 23, ROM), (Some(0xf133db73), Some(!0xf133db73))); - assert_eq!(crate::patch_frame(868, 24, ROM), (Some(0x40e1f01a), Some(!0x40e1f01a))); - assert_eq!(crate::patch_frame(868, 25, ROM), (Some(0x706e2647), Some(!0x706e2647))); - assert_eq!(crate::patch_frame(868, 26, ROM), (Some(0x827ab9f4), Some(!0x827ab9f4))); - assert_eq!(crate::patch_frame(868, 27, ROM), (Some(0x8da9315e), Some(!0x8da9315e))); - assert_eq!(crate::patch_frame(868, 28, ROM), (Some(0x4750a149), Some(!0x4750a149))); - assert_eq!(crate::patch_frame(868, 29, ROM), (Some(0x8ca23056), Some(!0x8ca23056))); - assert_eq!(crate::patch_frame(868, 30, ROM), (Some(0x93cb2de8), Some(!0x93cb2de8))); - assert_eq!(crate::patch_frame(868, 31, ROM), (Some(0xda43b371), Some(!0xda43b371))); - assert_eq!(crate::patch_frame(869, 0, ROM), (Some(0x3f7b6b66), Some(!0x3f7b6b66))); - assert_eq!(crate::patch_frame(869, 1, ROM), (Some(0xac6e99fa), Some(!0xac6e99fa))); - assert_eq!(crate::patch_frame(869, 2, ROM), (Some(0xf5c7e509), Some(!0xf5c7e509))); - assert_eq!(crate::patch_frame(869, 3, ROM), (Some(0x47ac1a6f), Some(!0x47ac1a6f))); - assert_eq!(crate::patch_frame(869, 4, ROM), (Some(0x0adcc2d6), Some(!0x0adcc2d6))); - assert_eq!(crate::patch_frame(869, 5, ROM), (Some(0xd17b0e03), Some(!0xd17b0e03))); - assert_eq!(crate::patch_frame(869, 6, ROM), (Some(0x9411683a), Some(!0x9411683a))); - assert_eq!(crate::patch_frame(869, 7, ROM), (Some(0xcb77e479), Some(!0xcb77e479))); - assert_eq!(crate::patch_frame(869, 8, ROM), (Some(0x10110fc9), Some(!0x10110fc9))); - assert_eq!(crate::patch_frame(869, 9, ROM), (Some(0x04e024a3), Some(!0x04e024a3))); - assert_eq!(crate::patch_frame(869, 10, ROM), (Some(0xd7551e75), Some(!0xd7551e75))); - assert_eq!(crate::patch_frame(869, 11, ROM), (Some(0x29fceabf), Some(!0x29fceabf))); - assert_eq!(crate::patch_frame(869, 12, ROM), (Some(0xcb247c5a), Some(!0xcb247c5a))); - assert_eq!(crate::patch_frame(869, 13, ROM), (Some(0xbf0b11da), Some(!0xbf0b11da))); - assert_eq!(crate::patch_frame(869, 14, ROM), (Some(0x1a2b24ec), Some(!0x1a2b24ec))); - assert_eq!(crate::patch_frame(869, 15, ROM), (Some(0x9bafd2f5), Some(!0x9bafd2f5))); - assert_eq!(crate::patch_frame(869, 16, ROM), (Some(0x8c146537), Some(!0x8c146537))); - assert_eq!(crate::patch_frame(869, 17, ROM), (Some(0x341f0ace), Some(!0x341f0ace))); - assert_eq!(crate::patch_frame(869, 18, ROM), (Some(0xcaaba4a2), Some(!0xcaaba4a2))); - assert_eq!(crate::patch_frame(869, 19, ROM), (Some(0x6cb0f989), Some(!0x6cb0f989))); - assert_eq!(crate::patch_frame(869, 20, ROM), (Some(0x753466d4), Some(!0x753466d4))); - assert_eq!(crate::patch_frame(869, 21, ROM), (Some(0x4c2159fe), Some(!0x4c2159fe))); - assert_eq!(crate::patch_frame(869, 22, ROM), (Some(0x60e3de47), Some(!0x60e3de47))); - assert_eq!(crate::patch_frame(869, 23, ROM), (Some(0x2c0da355), Some(!0x2c0da355))); - assert_eq!(crate::patch_frame(869, 24, ROM), (Some(0x4912a377), Some(!0x4912a377))); - assert_eq!(crate::patch_frame(869, 25, ROM), (Some(0x364f95f8), Some(!0x364f95f8))); - assert_eq!(crate::patch_frame(869, 26, ROM), (Some(0xc962bf7e), Some(!0xc962bf7e))); - assert_eq!(crate::patch_frame(869, 27, ROM), (Some(0x650ea97e), Some(!0x650ea97e))); - assert_eq!(crate::patch_frame(869, 28, ROM), (Some(0x0ea1c2f9), Some(!0x0ea1c2f9))); - assert_eq!(crate::patch_frame(869, 29, ROM), (Some(0x5d606c42), Some(!0x5d606c42))); - assert_eq!(crate::patch_frame(869, 30, ROM), (Some(0x0d308c5a), Some(!0x0d308c5a))); - assert_eq!(crate::patch_frame(869, 31, ROM), (Some(0x4770a3c6), Some(!0x4770a3c6))); - assert_eq!(crate::patch_frame(870, 0, ROM), (Some(0xea6466fc), Some(!0xea6466fc))); - assert_eq!(crate::patch_frame(870, 1, ROM), (Some(0x2aa05f79), Some(!0x2aa05f79))); - assert_eq!(crate::patch_frame(870, 2, ROM), (Some(0xcf5ec24e), Some(!0xcf5ec24e))); - assert_eq!(crate::patch_frame(870, 3, ROM), (Some(0xc32bd8d6), Some(!0xc32bd8d6))); - assert_eq!(crate::patch_frame(870, 4, ROM), (Some(0xe0e351f3), Some(!0xe0e351f3))); - assert_eq!(crate::patch_frame(870, 5, ROM), (Some(0xf022babf), Some(!0xf022babf))); - assert_eq!(crate::patch_frame(870, 6, ROM), (Some(0x3cb80ce8), Some(!0x3cb80ce8))); - assert_eq!(crate::patch_frame(870, 7, ROM), (Some(0x80f09746), Some(!0x80f09746))); - assert_eq!(crate::patch_frame(870, 8, ROM), (Some(0x52e65655), Some(!0x52e65655))); - assert_eq!(crate::patch_frame(870, 9, ROM), (Some(0x9fdf74b3), Some(!0x9fdf74b3))); - assert_eq!(crate::patch_frame(870, 10, ROM), (Some(0x8d01bfd4), Some(!0x8d01bfd4))); - assert_eq!(crate::patch_frame(870, 11, ROM), (Some(0x64bb7dbf), Some(!0x64bb7dbf))); - assert_eq!(crate::patch_frame(870, 12, ROM), (Some(0x4ff223af), Some(!0x4ff223af))); - assert_eq!(crate::patch_frame(870, 13, ROM), (Some(0xfda7288a), Some(!0xfda7288a))); - assert_eq!(crate::patch_frame(870, 14, ROM), (Some(0x6eaae04d), Some(!0x6eaae04d))); - assert_eq!(crate::patch_frame(870, 15, ROM), (Some(0xb32174ff), Some(!0xb32174ff))); - assert_eq!(crate::patch_frame(870, 16, ROM), (Some(0x22ff176e), Some(!0x22ff176e))); - assert_eq!(crate::patch_frame(870, 17, ROM), (Some(0x3d63236a), Some(!0x3d63236a))); - assert_eq!(crate::patch_frame(870, 18, ROM), (Some(0xc7210668), Some(!0xc7210668))); - assert_eq!(crate::patch_frame(870, 19, ROM), (Some(0x31734ade), Some(!0x31734ade))); - assert_eq!(crate::patch_frame(870, 20, ROM), (Some(0xbfe7e2fa), Some(!0xbfe7e2fa))); - assert_eq!(crate::patch_frame(870, 21, ROM), (Some(0x21a6aa11), Some(!0x21a6aa11))); - assert_eq!(crate::patch_frame(870, 22, ROM), (Some(0xd4500ed0), Some(!0xd4500ed0))); - assert_eq!(crate::patch_frame(870, 23, ROM), (Some(0x633e596c), Some(!0x633e596c))); - assert_eq!(crate::patch_frame(870, 24, ROM), (Some(0xf9c28134), Some(!0xf9c28134))); - assert_eq!(crate::patch_frame(870, 25, ROM), (Some(0x8368ba81), Some(!0x8368ba81))); - assert_eq!(crate::patch_frame(870, 26, ROM), (Some(0x4935cae8), Some(!0x4935cae8))); - assert_eq!(crate::patch_frame(870, 27, ROM), (Some(0x0bf74789), Some(!0x0bf74789))); - assert_eq!(crate::patch_frame(870, 28, ROM), (Some(0x8c4d4b62), Some(!0x8c4d4b62))); - assert_eq!(crate::patch_frame(870, 29, ROM), (Some(0x66da90a5), Some(!0x66da90a5))); - assert_eq!(crate::patch_frame(870, 30, ROM), (Some(0x468a6a04), Some(!0x468a6a04))); - assert_eq!(crate::patch_frame(870, 31, ROM), (Some(0xb450e92b), Some(!0xb450e92b))); - assert_eq!(crate::patch_frame(871, 0, ROM), (Some(0xc0e34c92), Some(!0xc0e34c92))); - assert_eq!(crate::patch_frame(871, 1, ROM), (Some(0x4d3f0cb7), Some(!0x4d3f0cb7))); - assert_eq!(crate::patch_frame(871, 2, ROM), (Some(0x1f232572), Some(!0x1f232572))); - assert_eq!(crate::patch_frame(871, 3, ROM), (Some(0xf9349b49), Some(!0xf9349b49))); - assert_eq!(crate::patch_frame(871, 4, ROM), (Some(0x858727fc), Some(!0x858727fc))); - assert_eq!(crate::patch_frame(871, 5, ROM), (Some(0x04484eb4), Some(!0x04484eb4))); - assert_eq!(crate::patch_frame(871, 6, ROM), (Some(0x4e788195), Some(!0x4e788195))); - assert_eq!(crate::patch_frame(871, 7, ROM), (Some(0xcc25c3b6), Some(!0xcc25c3b6))); - assert_eq!(crate::patch_frame(871, 8, ROM), (Some(0xb3dbe62b), Some(!0xb3dbe62b))); - assert_eq!(crate::patch_frame(871, 9, ROM), (Some(0x6d3d434f), Some(!0x6d3d434f))); - assert_eq!(crate::patch_frame(871, 10, ROM), (Some(0x326874e3), Some(!0x326874e3))); - assert_eq!(crate::patch_frame(871, 11, ROM), (Some(0xeb40dc4c), Some(!0xeb40dc4c))); - assert_eq!(crate::patch_frame(871, 12, ROM), (Some(0x3c97431f), Some(!0x3c97431f))); - assert_eq!(crate::patch_frame(871, 13, ROM), (Some(0x6296d457), Some(!0x6296d457))); - assert_eq!(crate::patch_frame(871, 14, ROM), (Some(0x4d3e4851), Some(!0x4d3e4851))); - assert_eq!(crate::patch_frame(871, 15, ROM), (Some(0xf71309e5), Some(!0xf71309e5))); - assert_eq!(crate::patch_frame(871, 16, ROM), (Some(0xbca315d0), Some(!0xbca315d0))); - assert_eq!(crate::patch_frame(871, 17, ROM), (Some(0xb9ec430d), Some(!0xb9ec430d))); - assert_eq!(crate::patch_frame(871, 18, ROM), (Some(0xabf3c735), Some(!0xabf3c735))); - assert_eq!(crate::patch_frame(871, 19, ROM), (Some(0x550dd5ef), Some(!0x550dd5ef))); - assert_eq!(crate::patch_frame(871, 20, ROM), (Some(0x03441112), Some(!0x03441112))); - assert_eq!(crate::patch_frame(871, 21, ROM), (Some(0x962cd927), Some(!0x962cd927))); - assert_eq!(crate::patch_frame(871, 22, ROM), (Some(0x811a2d2d), Some(!0x811a2d2d))); - assert_eq!(crate::patch_frame(871, 23, ROM), (Some(0xd7debecd), Some(!0xd7debecd))); - assert_eq!(crate::patch_frame(871, 24, ROM), (Some(0x5fafa327), Some(!0x5fafa327))); - assert_eq!(crate::patch_frame(871, 25, ROM), (Some(0xa61afdcb), Some(!0xa61afdcb))); - assert_eq!(crate::patch_frame(871, 26, ROM), (Some(0x799aa6bd), Some(!0x799aa6bd))); - assert_eq!(crate::patch_frame(871, 27, ROM), (Some(0xb68c2006), Some(!0xb68c2006))); - assert_eq!(crate::patch_frame(871, 28, ROM), (Some(0x8c99e814), Some(!0x8c99e814))); - assert_eq!(crate::patch_frame(871, 29, ROM), (Some(0x8da515f2), Some(!0x8da515f2))); - assert_eq!(crate::patch_frame(871, 30, ROM), (Some(0xc82a4baf), Some(!0xc82a4baf))); - assert_eq!(crate::patch_frame(871, 31, ROM), (Some(0xe5aa45e3), Some(!0xe5aa45e3))); + assert_eq!(crate::patch_frame(862, 0, &ROM), (Some(0x0d9235f6), Some(!0x0d9235f6))); + assert_eq!(crate::patch_frame(862, 1, &ROM), (Some(0xc31d68ce), Some(!0xc31d68ce))); + assert_eq!(crate::patch_frame(862, 2, &ROM), (Some(0x88de917a), Some(!0x88de917a))); + assert_eq!(crate::patch_frame(862, 3, &ROM), (Some(0x3690eea5), Some(!0x3690eea5))); + assert_eq!(crate::patch_frame(862, 4, &ROM), (Some(0xdc272627), Some(!0xdc272627))); + assert_eq!(crate::patch_frame(862, 5, &ROM), (Some(0x48691305), Some(!0x48691305))); + assert_eq!(crate::patch_frame(862, 6, &ROM), (Some(0x2467468f), Some(!0x2467468f))); + assert_eq!(crate::patch_frame(862, 7, &ROM), (Some(0x86a18342), Some(!0x86a18342))); + assert_eq!(crate::patch_frame(862, 8, &ROM), (Some(0xb60d73a5), Some(!0xb60d73a5))); + assert_eq!(crate::patch_frame(862, 9, &ROM), (Some(0xe81cd961), Some(!0xe81cd961))); + assert_eq!(crate::patch_frame(862, 10, &ROM), (Some(0xa4b1623d), Some(!0xa4b1623d))); + assert_eq!(crate::patch_frame(862, 11, &ROM), (Some(0xec69bf20), Some(!0xec69bf20))); + assert_eq!(crate::patch_frame(862, 12, &ROM), (Some(0xc1e34021), Some(!0xc1e34021))); + assert_eq!(crate::patch_frame(862, 13, &ROM), (Some(0x7ba472cc), Some(!0x7ba472cc))); + assert_eq!(crate::patch_frame(862, 14, &ROM), (Some(0x07dc6a88), Some(!0x07dc6a88))); + assert_eq!(crate::patch_frame(862, 15, &ROM), (Some(0x446bbcd0), Some(!0x446bbcd0))); + assert_eq!(crate::patch_frame(862, 16, &ROM), (Some(0x48183589), Some(!0x48183589))); + assert_eq!(crate::patch_frame(862, 17, &ROM), (Some(0xae0af240), Some(!0xae0af240))); + assert_eq!(crate::patch_frame(862, 18, &ROM), (Some(0x8631a617), Some(!0x8631a617))); + assert_eq!(crate::patch_frame(862, 19, &ROM), (Some(0xccb85cab), Some(!0xccb85cab))); + assert_eq!(crate::patch_frame(862, 20, &ROM), (Some(0x5946ceac), Some(!0x5946ceac))); + assert_eq!(crate::patch_frame(862, 21, &ROM), (Some(0x950a76f4), Some(!0x950a76f4))); + assert_eq!(crate::patch_frame(862, 22, &ROM), (Some(0xaf1c9ab4), Some(!0xaf1c9ab4))); + assert_eq!(crate::patch_frame(862, 23, &ROM), (Some(0xb895bdd6), Some(!0xb895bdd6))); + assert_eq!(crate::patch_frame(862, 24, &ROM), (Some(0xf22e71cc), Some(!0xf22e71cc))); + assert_eq!(crate::patch_frame(862, 25, &ROM), (Some(0xccc6abac), Some(!0xccc6abac))); + assert_eq!(crate::patch_frame(862, 26, &ROM), (Some(0x2b82c2b0), Some(!0x2b82c2b0))); + assert_eq!(crate::patch_frame(862, 27, &ROM), (Some(0xed830555), Some(!0xed830555))); + assert_eq!(crate::patch_frame(862, 28, &ROM), (Some(0xfa7af72a), Some(!0xfa7af72a))); + assert_eq!(crate::patch_frame(862, 29, &ROM), (Some(0xca7ceedf), Some(!0xca7ceedf))); + assert_eq!(crate::patch_frame(862, 30, &ROM), (Some(0x19d368ba), Some(!0x19d368ba))); + assert_eq!(crate::patch_frame(862, 31, &ROM), (Some(0x6a12fee7), Some(!0x6a12fee7))); + assert_eq!(crate::patch_frame(863, 0, &ROM), (Some(0x26a7d5da), Some(!0x26a7d5da))); + assert_eq!(crate::patch_frame(863, 1, &ROM), (Some(0x9b4b72a4), Some(!0x9b4b72a4))); + assert_eq!(crate::patch_frame(863, 2, &ROM), (Some(0xfd22eed4), Some(!0xfd22eed4))); + assert_eq!(crate::patch_frame(863, 3, &ROM), (Some(0x6a64a01d), Some(!0x6a64a01d))); + assert_eq!(crate::patch_frame(863, 4, &ROM), (Some(0x8c775416), Some(!0x8c775416))); + assert_eq!(crate::patch_frame(863, 5, &ROM), (Some(0x3543cd23), Some(!0x3543cd23))); + assert_eq!(crate::patch_frame(863, 6, &ROM), (Some(0xee1873c3), Some(!0xee1873c3))); + assert_eq!(crate::patch_frame(863, 7, &ROM), (Some(0xcb670abb), Some(!0xcb670abb))); + assert_eq!(crate::patch_frame(863, 8, &ROM), (Some(0x96156137), Some(!0x96156137))); + assert_eq!(crate::patch_frame(863, 9, &ROM), (Some(0x93d3bc93), Some(!0x93d3bc93))); + assert_eq!(crate::patch_frame(863, 10, &ROM), (Some(0x493788a9), Some(!0x493788a9))); + assert_eq!(crate::patch_frame(863, 11, &ROM), (Some(0xa934afda), Some(!0xa934afda))); + assert_eq!(crate::patch_frame(863, 12, &ROM), (Some(0x1ab9efde), Some(!0x1ab9efde))); + assert_eq!(crate::patch_frame(863, 13, &ROM), (Some(0x6b368753), Some(!0x6b368753))); + assert_eq!(crate::patch_frame(863, 14, &ROM), (Some(0x400795c3), Some(!0x400795c3))); + assert_eq!(crate::patch_frame(863, 15, &ROM), (Some(0x97cf98f4), Some(!0x97cf98f4))); + assert_eq!(crate::patch_frame(863, 16, &ROM), (Some(0xcea227d9), Some(!0xcea227d9))); + assert_eq!(crate::patch_frame(863, 17, &ROM), (Some(0x00fb4024), Some(!0x00fb4024))); + assert_eq!(crate::patch_frame(863, 18, &ROM), (Some(0x6fd1b9b7), Some(!0x6fd1b9b7))); + assert_eq!(crate::patch_frame(863, 19, &ROM), (Some(0x63d309a8), Some(!0x63d309a8))); + assert_eq!(crate::patch_frame(863, 20, &ROM), (Some(0x0242d707), Some(!0x0242d707))); + assert_eq!(crate::patch_frame(863, 21, &ROM), (Some(0x8af0663b), Some(!0x8af0663b))); + assert_eq!(crate::patch_frame(863, 22, &ROM), (Some(0x47611120), Some(!0x47611120))); + assert_eq!(crate::patch_frame(863, 23, &ROM), (Some(0xcfdfe216), Some(!0xcfdfe216))); + assert_eq!(crate::patch_frame(863, 24, &ROM), (Some(0x22098983), Some(!0x22098983))); + assert_eq!(crate::patch_frame(863, 25, &ROM), (Some(0xaa7294cb), Some(!0xaa7294cb))); + assert_eq!(crate::patch_frame(863, 26, &ROM), (Some(0x941862db), Some(!0x941862db))); + assert_eq!(crate::patch_frame(863, 27, &ROM), (Some(0xc6aec3dc), Some(!0xc6aec3dc))); + assert_eq!(crate::patch_frame(863, 28, &ROM), (Some(0xf65cfbbb), Some(!0xf65cfbbb))); + assert_eq!(crate::patch_frame(863, 29, &ROM), (Some(0xdaa7f6ce), Some(!0xdaa7f6ce))); + assert_eq!(crate::patch_frame(863, 30, &ROM), (Some(0x76a2f18c), Some(!0x76a2f18c))); + assert_eq!(crate::patch_frame(863, 31, &ROM), (Some(0xb6ff4233), Some(!0xb6ff4233))); + assert_eq!(crate::patch_frame(864, 0, &ROM), (Some(0x13730bca), Some(!0x13730bca))); + assert_eq!(crate::patch_frame(864, 1, &ROM), (Some(0x4cbfd7e0), Some(!0x4cbfd7e0))); + assert_eq!(crate::patch_frame(864, 2, &ROM), (Some(0xeee0df48), Some(!0xeee0df48))); + assert_eq!(crate::patch_frame(864, 3, &ROM), (Some(0x6835efad), Some(!0x6835efad))); + assert_eq!(crate::patch_frame(864, 4, &ROM), (Some(0x2ee4657b), Some(!0x2ee4657b))); + assert_eq!(crate::patch_frame(864, 5, &ROM), (Some(0x0fb803f9), Some(!0x0fb803f9))); + assert_eq!(crate::patch_frame(864, 6, &ROM), (Some(0xdb0e48ac), Some(!0xdb0e48ac))); + assert_eq!(crate::patch_frame(864, 7, &ROM), (Some(0x746a321c), Some(!0x746a321c))); + assert_eq!(crate::patch_frame(864, 8, &ROM), (Some(0x465b64e0), Some(!0x465b64e0))); + assert_eq!(crate::patch_frame(864, 9, &ROM), (Some(0x604109cd), Some(!0x604109cd))); + assert_eq!(crate::patch_frame(864, 10, &ROM), (Some(0x809d6405), Some(!0x809d6405))); + assert_eq!(crate::patch_frame(864, 11, &ROM), (Some(0x948de48a), Some(!0x948de48a))); + assert_eq!(crate::patch_frame(864, 12, &ROM), (Some(0x3e061591), Some(!0x3e061591))); + assert_eq!(crate::patch_frame(864, 13, &ROM), (Some(0xfcb767dc), Some(!0xfcb767dc))); + assert_eq!(crate::patch_frame(864, 14, &ROM), (Some(0x35f1da56), Some(!0x35f1da56))); + assert_eq!(crate::patch_frame(864, 15, &ROM), (Some(0x0e510eb8), Some(!0x0e510eb8))); + assert_eq!(crate::patch_frame(864, 16, &ROM), (Some(0xbee3aa43), Some(!0xbee3aa43))); + assert_eq!(crate::patch_frame(864, 17, &ROM), (Some(0x9617c529), Some(!0x9617c529))); + assert_eq!(crate::patch_frame(864, 18, &ROM), (Some(0x90b65f1d), Some(!0x90b65f1d))); + assert_eq!(crate::patch_frame(864, 19, &ROM), (Some(0xfa136451), Some(!0xfa136451))); + assert_eq!(crate::patch_frame(864, 20, &ROM), (Some(0x32f1596e), Some(!0x32f1596e))); + assert_eq!(crate::patch_frame(864, 21, &ROM), (Some(0x0f894e9b), Some(!0x0f894e9b))); + assert_eq!(crate::patch_frame(864, 22, &ROM), (Some(0x04dd507e), Some(!0x04dd507e))); + assert_eq!(crate::patch_frame(864, 23, &ROM), (Some(0x48053f56), Some(!0x48053f56))); + assert_eq!(crate::patch_frame(864, 24, &ROM), (Some(0x6b6fe57a), Some(!0x6b6fe57a))); + assert_eq!(crate::patch_frame(864, 25, &ROM), (Some(0xc9422783), Some(!0xc9422783))); + assert_eq!(crate::patch_frame(864, 26, &ROM), (Some(0x160e6b7d), Some(!0x160e6b7d))); + assert_eq!(crate::patch_frame(864, 27, &ROM), (Some(0xa3189368), Some(!0xa3189368))); + assert_eq!(crate::patch_frame(864, 28, &ROM), (Some(0x7179d3bd), Some(!0x7179d3bd))); + assert_eq!(crate::patch_frame(864, 29, &ROM), (Some(0x7da21cd4), Some(!0x7da21cd4))); + assert_eq!(crate::patch_frame(864, 30, &ROM), (Some(0xea9ffbd4), Some(!0xea9ffbd4))); + assert_eq!(crate::patch_frame(864, 31, &ROM), (Some(0xec6b3594), Some(!0xec6b3594))); + assert_eq!(crate::patch_frame(865, 0, &ROM), (Some(0x35553df6), Some(!0x35553df6))); + assert_eq!(crate::patch_frame(865, 1, &ROM), (Some(0x8e89d756), Some(!0x8e89d756))); + assert_eq!(crate::patch_frame(865, 2, &ROM), (Some(0x5f54c2d8), Some(!0x5f54c2d8))); + assert_eq!(crate::patch_frame(865, 3, &ROM), (Some(0x2d78815b), Some(!0x2d78815b))); + assert_eq!(crate::patch_frame(865, 4, &ROM), (Some(0xc4020b9a), Some(!0xc4020b9a))); + assert_eq!(crate::patch_frame(865, 5, &ROM), (Some(0x9db05552), Some(!0x9db05552))); + assert_eq!(crate::patch_frame(865, 6, &ROM), (Some(0xbda51a8f), Some(!0xbda51a8f))); + assert_eq!(crate::patch_frame(865, 7, &ROM), (Some(0x6f3692da), Some(!0x6f3692da))); + assert_eq!(crate::patch_frame(865, 8, &ROM), (Some(0x07561c3d), Some(!0x07561c3d))); + assert_eq!(crate::patch_frame(865, 9, &ROM), (Some(0x1f64c30f), Some(!0x1f64c30f))); + assert_eq!(crate::patch_frame(865, 10, &ROM), (Some(0xad09a9dc), Some(!0xad09a9dc))); + assert_eq!(crate::patch_frame(865, 11, &ROM), (Some(0xbcaacd45), Some(!0xbcaacd45))); + assert_eq!(crate::patch_frame(865, 12, &ROM), (Some(0xf660e9fa), Some(!0xf660e9fa))); + assert_eq!(crate::patch_frame(865, 13, &ROM), (Some(0x813dbf8c), Some(!0x813dbf8c))); + assert_eq!(crate::patch_frame(865, 14, &ROM), (Some(0x9ff6eb80), Some(!0x9ff6eb80))); + assert_eq!(crate::patch_frame(865, 15, &ROM), (Some(0x4b1fd7ab), Some(!0x4b1fd7ab))); + assert_eq!(crate::patch_frame(865, 16, &ROM), (Some(0x2c17d1bc), Some(!0x2c17d1bc))); + assert_eq!(crate::patch_frame(865, 17, &ROM), (Some(0xa5f48632), Some(!0xa5f48632))); + assert_eq!(crate::patch_frame(865, 18, &ROM), (Some(0x4f4d8a82), Some(!0x4f4d8a82))); + assert_eq!(crate::patch_frame(865, 19, &ROM), (Some(0x53239fa0), Some(!0x53239fa0))); + assert_eq!(crate::patch_frame(865, 20, &ROM), (Some(0x45b43c3d), Some(!0x45b43c3d))); + assert_eq!(crate::patch_frame(865, 21, &ROM), (Some(0x76ad4856), Some(!0x76ad4856))); + assert_eq!(crate::patch_frame(865, 22, &ROM), (Some(0x3edc0030), Some(!0x3edc0030))); + assert_eq!(crate::patch_frame(865, 23, &ROM), (Some(0x88cf0fb8), Some(!0x88cf0fb8))); + assert_eq!(crate::patch_frame(865, 24, &ROM), (Some(0x05c1d2e1), Some(!0x05c1d2e1))); + assert_eq!(crate::patch_frame(865, 25, &ROM), (Some(0xbaf40e0c), Some(!0xbaf40e0c))); + assert_eq!(crate::patch_frame(865, 26, &ROM), (Some(0x12069be4), Some(!0x12069be4))); + assert_eq!(crate::patch_frame(865, 27, &ROM), (Some(0x1aaa8f00), Some(!0x1aaa8f00))); + assert_eq!(crate::patch_frame(865, 28, &ROM), (Some(0x8dc1564e), Some(!0x8dc1564e))); + assert_eq!(crate::patch_frame(865, 29, &ROM), (Some(0x4f4c51a3), Some(!0x4f4c51a3))); + assert_eq!(crate::patch_frame(865, 30, &ROM), (Some(0x767b7bb8), Some(!0x767b7bb8))); + assert_eq!(crate::patch_frame(865, 31, &ROM), (Some(0xa8ad140c), Some(!0xa8ad140c))); + assert_eq!(crate::patch_frame(868, 0, &ROM), (Some(0x4019bf10), Some(!0x4019bf10))); + assert_eq!(crate::patch_frame(868, 1, &ROM), (Some(0xd6c583ee), Some(!0xd6c583ee))); + assert_eq!(crate::patch_frame(868, 2, &ROM), (Some(0x5916dd04), Some(!0x5916dd04))); + assert_eq!(crate::patch_frame(868, 3, &ROM), (Some(0xba87eb8d), Some(!0xba87eb8d))); + assert_eq!(crate::patch_frame(868, 4, &ROM), (Some(0xc01f0ec9), Some(!0xc01f0ec9))); + assert_eq!(crate::patch_frame(868, 5, &ROM), (Some(0x36ae63cc), Some(!0x36ae63cc))); + assert_eq!(crate::patch_frame(868, 6, &ROM), (Some(0x981863bf), Some(!0x981863bf))); + assert_eq!(crate::patch_frame(868, 7, &ROM), (Some(0xed7b259b), Some(!0xed7b259b))); + assert_eq!(crate::patch_frame(868, 8, &ROM), (Some(0x124eca40), Some(!0x124eca40))); + assert_eq!(crate::patch_frame(868, 9, &ROM), (Some(0x30520adf), Some(!0x30520adf))); + assert_eq!(crate::patch_frame(868, 10, &ROM), (Some(0xf71fdd2d), Some(!0xf71fdd2d))); + assert_eq!(crate::patch_frame(868, 11, &ROM), (Some(0x10b2283c), Some(!0x10b2283c))); + assert_eq!(crate::patch_frame(868, 12, &ROM), (Some(0x44350ebe), Some(!0x44350ebe))); + assert_eq!(crate::patch_frame(868, 13, &ROM), (Some(0x820b8896), Some(!0x820b8896))); + assert_eq!(crate::patch_frame(868, 14, &ROM), (Some(0x75023c17), Some(!0x75023c17))); + assert_eq!(crate::patch_frame(868, 15, &ROM), (Some(0x829c2a83), Some(!0x829c2a83))); + assert_eq!(crate::patch_frame(868, 16, &ROM), (Some(0x293fb0b0), Some(!0x293fb0b0))); + assert_eq!(crate::patch_frame(868, 17, &ROM), (Some(0xafa075bc), Some(!0xafa075bc))); + assert_eq!(crate::patch_frame(868, 18, &ROM), (Some(0xb2b315ed), Some(!0xb2b315ed))); + assert_eq!(crate::patch_frame(868, 19, &ROM), (Some(0xd538494e), Some(!0xd538494e))); + assert_eq!(crate::patch_frame(868, 20, &ROM), (Some(0x3a5e3aa5), Some(!0x3a5e3aa5))); + assert_eq!(crate::patch_frame(868, 21, &ROM), (Some(0x7e161713), Some(!0x7e161713))); + assert_eq!(crate::patch_frame(868, 22, &ROM), (Some(0xae98802d), Some(!0xae98802d))); + assert_eq!(crate::patch_frame(868, 23, &ROM), (Some(0x8d06ee4d), Some(!0x8d06ee4d))); + assert_eq!(crate::patch_frame(868, 24, &ROM), (Some(0xae1f95e8), Some(!0xae1f95e8))); + assert_eq!(crate::patch_frame(868, 25, &ROM), (Some(0xaa805c18), Some(!0xaa805c18))); + assert_eq!(crate::patch_frame(868, 26, &ROM), (Some(0xfc3dee4e), Some(!0xfc3dee4e))); + assert_eq!(crate::patch_frame(868, 27, &ROM), (Some(0x30aa3310), Some(!0x30aa3310))); + assert_eq!(crate::patch_frame(868, 28, &ROM), (Some(0x709a90ac), Some(!0x709a90ac))); + assert_eq!(crate::patch_frame(868, 29, &ROM), (Some(0xecee4d75), Some(!0xecee4d75))); + assert_eq!(crate::patch_frame(868, 30, &ROM), (Some(0xda819841), Some(!0xda819841))); + assert_eq!(crate::patch_frame(868, 31, &ROM), (Some(0xcb47a884), Some(!0xcb47a884))); + assert_eq!(crate::patch_frame(869, 0, &ROM), (Some(0xfd9c6175), Some(!0xfd9c6175))); + assert_eq!(crate::patch_frame(869, 1, &ROM), (Some(0x07daeaa9), Some(!0x07daeaa9))); + assert_eq!(crate::patch_frame(869, 2, &ROM), (Some(0x276de0e5), Some(!0x276de0e5))); + assert_eq!(crate::patch_frame(869, 3, &ROM), (Some(0x5f345925), Some(!0x5f345925))); + assert_eq!(crate::patch_frame(869, 4, &ROM), (Some(0x7d7cbf0e), Some(!0x7d7cbf0e))); + assert_eq!(crate::patch_frame(869, 5, &ROM), (Some(0xeb43a719), Some(!0xeb43a719))); + assert_eq!(crate::patch_frame(869, 6, &ROM), (Some(0x5ae87db9), Some(!0x5ae87db9))); + assert_eq!(crate::patch_frame(869, 7, &ROM), (Some(0x6e2bc942), Some(!0x6e2bc942))); + assert_eq!(crate::patch_frame(869, 8, &ROM), (Some(0x493ff893), Some(!0x493ff893))); + assert_eq!(crate::patch_frame(869, 9, &ROM), (Some(0x471efa7e), Some(!0x471efa7e))); + assert_eq!(crate::patch_frame(869, 10, &ROM), (Some(0x5c287854), Some(!0x5c287854))); + assert_eq!(crate::patch_frame(869, 11, &ROM), (Some(0x18ff6afa), Some(!0x18ff6afa))); + assert_eq!(crate::patch_frame(869, 12, &ROM), (Some(0xb3cf86ea), Some(!0xb3cf86ea))); + assert_eq!(crate::patch_frame(869, 13, &ROM), (Some(0xbdf65d71), Some(!0xbdf65d71))); + assert_eq!(crate::patch_frame(869, 14, &ROM), (Some(0x01a99dcf), Some(!0x01a99dcf))); + assert_eq!(crate::patch_frame(869, 15, &ROM), (Some(0x87dc6b2c), Some(!0x87dc6b2c))); + assert_eq!(crate::patch_frame(869, 16, &ROM), (Some(0x083c04f3), Some(!0x083c04f3))); + assert_eq!(crate::patch_frame(869, 17, &ROM), (Some(0x59336c37), Some(!0x59336c37))); + assert_eq!(crate::patch_frame(869, 18, &ROM), (Some(0xcbb5a917), Some(!0xcbb5a917))); + assert_eq!(crate::patch_frame(869, 19, &ROM), (Some(0xb642a7ee), Some(!0xb642a7ee))); + assert_eq!(crate::patch_frame(869, 20, &ROM), (Some(0x5aae62b3), Some(!0x5aae62b3))); + assert_eq!(crate::patch_frame(869, 21, &ROM), (Some(0x8a0bfc6f), Some(!0x8a0bfc6f))); + assert_eq!(crate::patch_frame(869, 22, &ROM), (Some(0x81be4455), Some(!0x81be4455))); + assert_eq!(crate::patch_frame(869, 23, &ROM), (Some(0xcf4fbebd), Some(!0xcf4fbebd))); + assert_eq!(crate::patch_frame(869, 24, &ROM), (Some(0xd9df85c7), Some(!0xd9df85c7))); + assert_eq!(crate::patch_frame(869, 25, &ROM), (Some(0x08f655a1), Some(!0x08f655a1))); + assert_eq!(crate::patch_frame(869, 26, &ROM), (Some(0x7abec84f), Some(!0x7abec84f))); + assert_eq!(crate::patch_frame(869, 27, &ROM), (Some(0xbf78c75d), Some(!0xbf78c75d))); + assert_eq!(crate::patch_frame(869, 28, &ROM), (Some(0x5064d1e3), Some(!0x5064d1e3))); + assert_eq!(crate::patch_frame(869, 29, &ROM), (Some(0x81187e16), Some(!0x81187e16))); + assert_eq!(crate::patch_frame(869, 30, &ROM), (Some(0xc941d87f), Some(!0xc941d87f))); + assert_eq!(crate::patch_frame(869, 31, &ROM), (Some(0x64c4998d), Some(!0x64c4998d))); + assert_eq!(crate::patch_frame(870, 0, &ROM), (Some(0xf6d42fed), Some(!0xf6d42fed))); + assert_eq!(crate::patch_frame(870, 1, &ROM), (Some(0xed4ff133), Some(!0xed4ff133))); + assert_eq!(crate::patch_frame(870, 2, &ROM), (Some(0x85990dc8), Some(!0x85990dc8))); + assert_eq!(crate::patch_frame(870, 3, &ROM), (Some(0xe1087d13), Some(!0xe1087d13))); + assert_eq!(crate::patch_frame(870, 4, &ROM), (Some(0x412a3efa), Some(!0x412a3efa))); + assert_eq!(crate::patch_frame(870, 5, &ROM), (Some(0xd61c580c), Some(!0xd61c580c))); + assert_eq!(crate::patch_frame(870, 6, &ROM), (Some(0x98a93558), Some(!0x98a93558))); + assert_eq!(crate::patch_frame(870, 7, &ROM), (Some(0xa5257f15), Some(!0xa5257f15))); + assert_eq!(crate::patch_frame(870, 8, &ROM), (Some(0x88ab2780), Some(!0x88ab2780))); + assert_eq!(crate::patch_frame(870, 9, &ROM), (Some(0xda27e440), Some(!0xda27e440))); + assert_eq!(crate::patch_frame(870, 10, &ROM), (Some(0x2960a1e6), Some(!0x2960a1e6))); + assert_eq!(crate::patch_frame(870, 11, &ROM), (Some(0x400d97d4), Some(!0x400d97d4))); + assert_eq!(crate::patch_frame(870, 12, &ROM), (Some(0x1070f2f0), Some(!0x1070f2f0))); + assert_eq!(crate::patch_frame(870, 13, &ROM), (Some(0x20d25408), Some(!0x20d25408))); + assert_eq!(crate::patch_frame(870, 14, &ROM), (Some(0xe3239384), Some(!0xe3239384))); + assert_eq!(crate::patch_frame(870, 15, &ROM), (Some(0x1b015cad), Some(!0x1b015cad))); + assert_eq!(crate::patch_frame(870, 16, &ROM), (Some(0xe0e4d458), Some(!0xe0e4d458))); + assert_eq!(crate::patch_frame(870, 17, &ROM), (Some(0x6c417ff1), Some(!0x6c417ff1))); + assert_eq!(crate::patch_frame(870, 18, &ROM), (Some(0x39bb1469), Some(!0x39bb1469))); + assert_eq!(crate::patch_frame(870, 19, &ROM), (Some(0x839167fe), Some(!0x839167fe))); + assert_eq!(crate::patch_frame(870, 20, &ROM), (Some(0x2165c6ff), Some(!0x2165c6ff))); + assert_eq!(crate::patch_frame(870, 21, &ROM), (Some(0xf72b86d5), Some(!0xf72b86d5))); + assert_eq!(crate::patch_frame(870, 22, &ROM), (Some(0xc6f16ae2), Some(!0xc6f16ae2))); + assert_eq!(crate::patch_frame(870, 23, &ROM), (Some(0xa999f0b4), Some(!0xa999f0b4))); + assert_eq!(crate::patch_frame(870, 24, &ROM), (Some(0xfee7994a), Some(!0xfee7994a))); + assert_eq!(crate::patch_frame(870, 25, &ROM), (Some(0x838939e9), Some(!0x838939e9))); + assert_eq!(crate::patch_frame(870, 26, &ROM), (Some(0x3512131c), Some(!0x3512131c))); + assert_eq!(crate::patch_frame(870, 27, &ROM), (Some(0x506f71ad), Some(!0x506f71ad))); + assert_eq!(crate::patch_frame(870, 28, &ROM), (Some(0x82a3f713), Some(!0x82a3f713))); + assert_eq!(crate::patch_frame(870, 29, &ROM), (Some(0xb39c3a7c), Some(!0xb39c3a7c))); + assert_eq!(crate::patch_frame(870, 30, &ROM), (Some(0x0a477d63), Some(!0x0a477d63))); + assert_eq!(crate::patch_frame(870, 31, &ROM), (Some(0x89f017cd), Some(!0x89f017cd))); + assert_eq!(crate::patch_frame(871, 0, &ROM), (Some(0x3305c0b0), Some(!0x3305c0b0))); + assert_eq!(crate::patch_frame(871, 1, &ROM), (Some(0xe838b447), Some(!0xe838b447))); + assert_eq!(crate::patch_frame(871, 2, &ROM), (Some(0x9b93ada5), Some(!0x9b93ada5))); + assert_eq!(crate::patch_frame(871, 3, &ROM), (Some(0x09e85064), Some(!0x09e85064))); + assert_eq!(crate::patch_frame(871, 4, &ROM), (Some(0xf8823512), Some(!0xf8823512))); + assert_eq!(crate::patch_frame(871, 5, &ROM), (Some(0x7576d938), Some(!0x7576d938))); + assert_eq!(crate::patch_frame(871, 6, &ROM), (Some(0x50dd3edc), Some(!0x50dd3edc))); + assert_eq!(crate::patch_frame(871, 7, &ROM), (Some(0xe9c4e273), Some(!0xe9c4e273))); + assert_eq!(crate::patch_frame(871, 8, &ROM), (Some(0x639cfc43), Some(!0x639cfc43))); + assert_eq!(crate::patch_frame(871, 9, &ROM), (Some(0x257146c0), Some(!0x257146c0))); + assert_eq!(crate::patch_frame(871, 10, &ROM), (Some(0xd2a256ef), Some(!0xd2a256ef))); + assert_eq!(crate::patch_frame(871, 11, &ROM), (Some(0x9a5d9e99), Some(!0x9a5d9e99))); + assert_eq!(crate::patch_frame(871, 12, &ROM), (Some(0xb871bf64), Some(!0xb871bf64))); + assert_eq!(crate::patch_frame(871, 13, &ROM), (Some(0x206d95e2), Some(!0x206d95e2))); + assert_eq!(crate::patch_frame(871, 14, &ROM), (Some(0x24e16026), Some(!0x24e16026))); + assert_eq!(crate::patch_frame(871, 15, &ROM), (Some(0x2535379e), Some(!0x2535379e))); + assert_eq!(crate::patch_frame(871, 16, &ROM), (Some(0x35b20035), Some(!0x35b20035))); + assert_eq!(crate::patch_frame(871, 17, &ROM), (Some(0x9bf08a38), Some(!0x9bf08a38))); + assert_eq!(crate::patch_frame(871, 18, &ROM), (Some(0x144e91ba), Some(!0x144e91ba))); + assert_eq!(crate::patch_frame(871, 19, &ROM), (Some(0x16458f39), Some(!0x16458f39))); + assert_eq!(crate::patch_frame(871, 20, &ROM), (Some(0x0b60cfdd), Some(!0x0b60cfdd))); + assert_eq!(crate::patch_frame(871, 21, &ROM), (Some(0xbb0611cb), Some(!0xbb0611cb))); + assert_eq!(crate::patch_frame(871, 22, &ROM), (Some(0x642fe6d0), Some(!0x642fe6d0))); + assert_eq!(crate::patch_frame(871, 23, &ROM), (Some(0xbcaaf246), Some(!0xbcaaf246))); + assert_eq!(crate::patch_frame(871, 24, &ROM), (Some(0x19eb9534), Some(!0x19eb9534))); + assert_eq!(crate::patch_frame(871, 25, &ROM), (Some(0xb978d685), Some(!0xb978d685))); + assert_eq!(crate::patch_frame(871, 26, &ROM), (Some(0x6c770aec), Some(!0x6c770aec))); + assert_eq!(crate::patch_frame(871, 27, &ROM), (Some(0xd42e9be6), Some(!0xd42e9be6))); + assert_eq!(crate::patch_frame(871, 28, &ROM), (Some(0xc7b232d0), Some(!0xc7b232d0))); + assert_eq!(crate::patch_frame(871, 29, &ROM), (Some(0xdd5ba29c), Some(!0xdd5ba29c))); + assert_eq!(crate::patch_frame(871, 30, &ROM), (Some(0x1100aa46), Some(!0x1100aa46))); + assert_eq!(crate::patch_frame(871, 31, &ROM), (Some(0xc38ee979), Some(!0xc38ee979))); // also test the null case, frame 0 should typically have no mappings. - assert_eq!(crate::patch_frame(0x0, 0, ROM), (None, None) ); + assert_eq!(crate::patch_frame(0x0, 0, &ROM), (None, None) ); } } diff --git a/services/root-keys/src/lib.rs b/services/root-keys/src/lib.rs index abcc719d5..a4becc230 100644 --- a/services/root-keys/src/lib.rs +++ b/services/root-keys/src/lib.rs @@ -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}; diff --git a/services/root-keys/src/main.rs b/services/root-keys/src/main.rs index 5590e1198..8026a5843 100644 --- a/services/root-keys/src/main.rs +++ b/services/root-keys/src/main.rs @@ -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(); } diff --git a/services/shellchat/src/cmds/keys.rs b/services/shellchat/src/cmds/keys.rs index 9fb9a5416..4419003fc 100644 --- a/services/shellchat/src/cmds/keys.rs +++ b/services/shellchat/src/cmds/keys.rs @@ -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(); diff --git a/services/spinor/src/lib.rs b/services/spinor/src/lib.rs index db82bd175..40cc2b868 100644 --- a/services/spinor/src/lib.rs +++ b/services/spinor/src/lib.rs @@ -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);